I have this code
package main
import "fmt"
type Foo struct {
Bar string
}
func (f *Foo) level4() {
fmt.Printf("Bar = %s\n", f.Bar)
}
func (f *Foo) level3() {
f.level4() // panics here, 2 levels down
}
func (f *Foo) level2() {
f.level3()
}
func (f *Foo) level1() {
f.level2()
}
type FooWrapper struct {
foo *Foo
}
func main() {
w := FooWrapper{}
w.foo.level1() // expected it to panic here, since foo is nil
}
As expected, running this gives
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x47f454]
However, I expected the nil pointer dereference to happen at w.foo.level1(), since foo is nil. Instead, it calls levels 1, 2 and 3 and panics there. Why is this the case?
playground link
Why is this the case?
Because w.foo.level1() is valid statement and similarly f.level2(), f.level3(), f.level4() are also a valid statement.
try this
func (f *Foo) level1() {
println("Hello Go")
f.level2()
}
it will print Hello Go and call f.level2() and also see last call level 4
func (f *Foo) level4() {
println("Hello Go 4")
fmt.Printf("Bar = %s\n", f.Bar)
}
it will print Hello Go 4 but panic on next line it is showing the trace or you can say origin of error
The default value of any pointer type is nil.
As you are constructing your object using
w := FooWrapper{}
The value of foo will be assigned the default nil.
To resolve the problem you should pass a value for foo.
w := FooWrapper{foo: &Foo{Bar: "bar"}}
What I usually do to prevent this issue is to make some constructor function.
func NewFooWrapper() *FooWrapper {
return &FooWrapper{foo: &Foo{Bar: "bar"}}
}
w := NewFooWrapper()
Or in case the value of foo can't be hardcoded.
func NewFooWrapper(foo *Foo) *FooWrapper {
return &FooWrapper{foo: foo}
}
w := NewFooWrapper(&Foo{Bar: "bar"})
This makes it more explicit from a coding point of view preventing these errors in other places of code.
You did not initialize the FooWrapper in your main function correctly. Your foo field with type *Foo is nil inside w variable type of FooWrapper because you have not assigned a value for that and the default value for a pointer type variable is nil in Go
Simple correct initialization as follows
w := FooWrapper{
foo: &Foo{
Bar: "bar",
},
}
run in playground
output :
Bar = bar
The reason that panic doesn't come in level1(), level2(), level3() is because they are not using any Foo's fields inside those functions. And also in level4() panic occurs not because of the function call, but because it's using f.Bar in print.
In Go,
If the concrete value inside the interface itself is nil, the method will be called with a nil receiver.
You can find a simple example for this in https://go.dev/tour/methods/12
And also you can find a great explanation for this in Go specs documentation under Calls
A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m. If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m()
Related
My question is similar to How to initialize struct pointer via reflection.
I have an interface that represents a nil pointer. I want to update the value behind the nil pointer.
I took the code from one of the examples in the answers to the question mentioned above, but my situation is slightly different, and the given solution isn't working.
Inside InitNilPointer() the value actually does become &Foo{}. But the result at the call site remains (*Foo)(nil). How can I use reflect to update foo in main() to &Foo{}?
The situation is the following
func main() {
var foo *Foo
InitNilPointer(foo)
// Want: &main.Foo{A:""}
fmt.Printf("Want: %+#v\n", &Foo{})
// Got: (*main.Foo)(nil)
fmt.Printf("Got: %+#v\n", foo)
}
// InitNilPointer initiates the given pointer to a nil value to become a pointer to
// a value. E.g. (*Foo)(nil) becomes &Foo{}.
func InitNilPointer(source interface{}) {
v := reflect.ValueOf(source)
if reflect.Indirect(v).IsValid() {
return
}
rv := reflect.ValueOf(&source).Elem()
t := rv.Elem().Type().Elem()
// This only updates the value locally. The call site still has a nil pointer. SAD.
rv.Set(reflect.New(t))
// source: &main.Foo{A:""}
fmt.Printf("source: %+#v\n", source)
}
Whatever you pass to a function, a copy is made. If you pass foo, no matter what the function does, it can only modify the copy but not the original foo variable.
So you must pass &foo (and modifying the pointed object will modify foo):
func main() {
var foo *Foo
InitNilPointer(&foo)
fmt.Printf("Want: %+#v\n", &Foo{})
fmt.Printf("Got: %+#v\n", foo)
}
func InitNilPointer(source interface{}) {
rv := reflect.ValueOf(source).Elem()
if reflect.Indirect(rv).IsValid() {
return
}
t := rv.Type().Elem()
rv.Set(reflect.New(t))
// source: &main.Foo{A:""}
fmt.Printf("source: %+#v\n", source)
}
This will output (try it on the Go Playground):
source: (**main.Foo)(0xc00000e028)
Want: &main.Foo{A:""}
Got: &main.Foo{A:""}
I want to instantiate an object in Go using reflection and call a method on it. However, I have no idea how to do this. I have tried something, but it does not work.
type foo struct {
name string
}
func (f *foo) Bar() {
f.name = "baz"
fmt.Println("hi " + f.name)
}
func main() {
t := reflect.TypeOf(&foo{})
fooElement := reflect.New(t).Elem()
fooElement.MethodByName("Bar").Call([]reflect.Value{})
}
reflect.New works exactly like the new function, in that it returns an allocated pointer to the given type. This means you want pass the struct, not a pointer to the struct, to reflect.TypeOf.
t := reflect.TypeOf(foo{})
fooV := reflect.New(t)
Since you now have a pointer value of the correct type, you can call the method directly:
fooV.MethodByName("Bar").Call(nil)
https://play.golang.org/p/Aehrls4A8xB
I'm a bit perplexed by this go code. I have a struct (Outer) with an embedded struct (Inner), but when I initialize Outer, I intentionally leave the embedded struct uninitialized.
type Inner struct {
value int
}
func (i *Inner) MyFunc() string {
return "inner"
}
func (i *Inner) OnlyInner() string {
return "only inner stuff"
}
type Outer struct {
*Inner
}
func (o *Outer) MyFunc() string {
return "outer"
}
func main() {
// embedded struct is *not* initialized
o := &Outer{}
fmt.Println(o.Inner)
fmt.Println(o.Inner.MyFunc())
fmt.Println(o.Inner.OnlyInner())
//fmt.Println(o.Inner.value)
}
Output:
<nil>
inner
only inner stuff
And if I uncomment the last line (with o.Inner.value), I get a nil pointer dereference error.
What's up here? The effective go page says (https://golang.org/doc/effective_go.html#embedding):
When we embed a type, the methods of that type become methods of the outer type, but when they are invoked the receiver of the method is the inner type, not the outer one.
It seems like in my case, the inner type is <nil>, yet the method calls execute without problem. What's going on under the hood?
A method can be called with a nil receiver, as long as you do not dereference the receiver itself.
This means that the following works playground:
package main
import (
"fmt"
)
type foo struct {
val int
}
func (f *foo) Print() {
fmt.Println("Receiver:", f)
}
func (f *foo) PrintVal() {
fmt.Println("Val: ", f.val)
}
func main() {
var f *foo
f.Print()
//f.PrintVal()
}
f.Print() works without issues since we're just printing a pointer, we're not trying to dereference it.
However, f.PrintVal attempts to dereference a nil pointer, causing a panic.
When in doubt, remember that the methods in this example are equivalent to functions that take the receiver as first parameter:
func Print(f *foo)
func PrintVal(f *foo)
This is mentioned in the spec under method declarations:
The type of a method is the type of a function with the receiver as
first argument. For instance, the method Scale has type
func(p *Point, factor float64)
However, a function declared this way
is not a method.
This makes it clear that the receiver is nothing special, it can be nil as long as you don't dereference it.
The methods of the uninitialized struct are being called with a nil-receiver. If in the methods used that receiver you would get a panic. It is valid to call a method using a nil receiver, and the method could modify its behavior by checking if the receiver is nil.
Can an instance of a go type change its underlying value? Thanks to a previous question I know I can make my function's receiver a pointer and change struct fields if my type is a struct.
However, I'm interesting in changing the underlying type's value. Consider a small program like this
type Foo string
func (f *Foo) ChangeMe() {
val := Foo("Hello World")
f = &val
//fmt.Println(*f)
}
func main() {
f := Foo("Nope")
f.ChangeMe()
fmt.Println(f)
}
My naive assumption was "OK, I've created a new Foo("Hello World") and then pointed f at it. Since receiver is a pointer (*Foo), this should change the value in main().
However, this does not work. The above program still prints out "Nope"
Interested both in what my incorrect assumption about go are, and any techniques for achieving what I want to do.
You're assigning a new pointer value to f instead of dereferencing it.
Dereference f and assign a new string value:
func (f *Foo) ChangeMe() {
*f = Foo("Hello World")
}
Need help understanding why this breaks. PrintFoo can be called using either pointer or value. Why not NumField?
http://play.golang.org/p/Kw16ReujRx
type A struct {
foo string
}
func (a *A) PrintFoo(){
fmt.Println("Foo value is " + a.foo)
}
func main() {
a := &A{foo: "afoo"}
(*a).PrintFoo() //Works - no problem
a.PrintFoo() //Works - no problem
reflect.TypeOf(*a).NumField() //Works - no problem - Type = main.A
reflect.TypeOf(a).NumField() //BREAKS! - Type = *main.A
}
From the documentation :
// NumField returns the number of fields in the struct v.
// It panics if v's Kind is not Struct.
func (v Value) NumField() int
You are calling it on a pointer, you have to call it on a struct instead, for example :
fmt.Println(reflect.Indirect(reflect.ValueOf(a)).NumField())
fmt.Println(reflect.Indirect(reflect.ValueOf(*a)).NumField())
When you're not sure if your value is a pointer or not, use reflect.Indirect:
Indirect returns the value that v points to. If v is a nil pointer,
Indirect returns a zero Value. If v is not a pointer, Indirect returns
v.
//edit:
NumField gets called on Value, not your actual object, for example of you do:
func main() {
a := &A{foo: "afoo"}
fmt.Printf("%#v\n", reflect.TypeOf(*a))
fmt.Printf("%#v\n", reflect.TypeOf(a))
}
You will get :
//*a
&reflect.rtype{size:0x8, ...... ptrToThis:(*reflect.rtype)(0xec320)}
//a
&reflect.rtype{size:0x4, ...... ptrToThis:(*reflect.rtype)(nil)}
As you can tell, it's a completely different beast.
The first one holds information about the pointer, hence ptrToThis points to the actual struct.
The second holds info about the struct itself.