I'm trying to set an internal value of an interface to nil
something like the following :
typ := &TYP{InternalState: "filled"}
setNil(typ)
fmt.Printf("Expecting that %v to be nil", typ)
And I need to know how to implement the setNil(typ interface{})
method.
For more details see this code in play.golang.org.
Under the hood, an interface in Golang consists of two elements: type and value. When we assign a nil integer pointer to an interface in our example above, the interface becomes (*int)(nil) , and it is not nil. An interface equals nil only if both the type and value are nil.
We want to accept the address (pointer) of the pointer variable, which is something like **SomeType . To actually be able to assign a new value ( nil ) to the pointer variable, we have to dereference it ( * operator).
In the Go programming language, nil is a zero value. Recall from unit 2 that an integer declared without a value will default to 0. An empty string is the zero value for strings, and so on. A pointer with nowhere to point has the value nil .
nil is a frequently used and important predeclared identifier in Go. It is the literal representation of zero values of many kinds of types. Many new Go programmers with experiences of some other popular languages may view nil as the counterpart of null (or NULL ) in other languages.
The thing is you don't have an interface value. You have a pointer value, a pointer to a concrete type. That is not the same as an interface value.
If you want to change the value of a variable of any type, you have to pass a pointer to it. This also includes variables of interface type, and also variables of pointer type. This is one of those very rare cases when a pointer to interface{}
makes sense (*interface{}
), in fact it's inevitable.
But if your function expects an interface and you pass a non-interface value, an interface value will be created implicitly and you could only nil
this implicitly created value.
So we have 2 different / distinct cases:
nil
an interface{}
func setNilIf(v *interface{}) {
*v = nil
}
Using it:
var i interface{} = "Bob"
fmt.Printf("Before: %v\n", i)
setNilIf(&i)
fmt.Printf("After: %v\n", i)
Output:
Before: Bob
After: <nil>
So it works.
nil
a pointer; using unsafe
Actually this is your case. We want to change the value of a variable of pointer type. To accept a pointer to any type, we can use unsafe.Pointer
. unsafe.Pointer
is a language support, it's a special pointer type which can be converted from and to any pointer type.
We want to accept the address (pointer) of the pointer variable, which is something like **SomeType
. To actually be able to assign a new value (nil
) to the pointer variable, we have to dereference it (*
operator). But unsafe.Pointer
cannot be dereferenced, so first we have to convert it to a pointer to pointer to "something", but since we only want to assign nil
(which is the same to all pointer types regardless of the type of the pointed value), the "something" doesn't matter, I will just use int
, and so I will convert the unsafe.Pointer
pointer value to **int
.
func setNilPtr(p unsafe.Pointer) {
*(**int)(p) = nil
}
Using it:
typ := &TYP{InternalState: "filled"}
fmt.Printf("Before: %v\n", typ)
setNilPtr(unsafe.Pointer(&typ))
fmt.Printf("After: %v\n", typ)
Output:
Before: &{filled}
After: <nil>
So this one also works. There is still another way using reflection:
nil
a pointer; using reflect
You can also nil
a pointer using reflection only (reflect
package). We still have to pass the address of the variable of pointer type. Note that in this case the type of the parameter will simply be interface{}
. And it will contain a dynamic type like **SomeType
. Since pointers have zero value nil
, we can obtain such a value with reflect.Zero()
which we will set using Value.Set()
:
func setNilPtr2(i interface{}) {
v := reflect.ValueOf(i)
v.Elem().Set(reflect.Zero(v.Elem().Type()))
}
Using it:
typ2 := &TYP{InternalState: "filled"}
fmt.Printf("Before: %v\n", typ2)
setNilPtr2(&typ2)
fmt.Printf("After: %v\n", typ2)
Output:
Before: &{filled}
After: <nil>
So this one also works. Try these on the Go Playground.
But seriously: if you want to nil
something, assign nil
to it. Do not complicate things unnecessarily.
i = nil
typ = nil
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With