Set the interface to zero in Golang

I am trying to set the internal interface value for nil like this:

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 setNil(typ interface{}) .

See this code at play.golang.org for more details .

+5
source share
1 answer

The fact is that you do not have an interface value. You have a pointer value, a pointer to a specific type. This is not the same as the meaning of the interface.

If you want to change the value of a variable of any type, you need to pass a pointer to it. This also includes interface type variables as well as pointer type variables. This is one of those rare cases where a pointer to interface{} makes sense ( *interface{} ), in fact it is inevitable.

But if your function expects an interface and you pass the value without the interface, the value of the interface will be created implicitly, and you could only nil this implicitly created value.

So, we have two different / separate cases:

nil a interface{} function

 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.

Function to nil pointer; using unsafe

This is actually your business. We want to change the value of a pointer type variable. To accept a pointer to any type, we can use unsafe.Pointer . unsafe.Pointer is a language support , it is a special type of pointer that can be converted from any type of pointer.

We want to accept the address (pointer) of a pointer variable, something like **SomeType . To actually assign a pointer variable a new value ( nil ), we must dereference it ( * operator). But unsafe.Pointer cannot be dereferenced, so first we need to convert it to a pointer to a pointer to "something", but since we only want to assign nil (which is the same for all types of pointers, regardless of the type of pointed value), "which that "doesn’t matter, I just use int , and so I convert the unsafe.Pointer pointer unsafe.Pointer 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 it works too. There is another way to use reflection:

Function to nil pointer; using reflect

You can also use the nil pointer to use only reflection. We still need to pass the address of a pointer type variable. Note that in this case, the parameter type will be just interface{} . And it will contain the dynamic type type **SomeType . Since pointers have a nil value of zero, we can get the value reflect.Zero() that 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 it works too. Try them on the go playground .


But seriously: if you want to nil something, assign nil . Do not complicate things unnecessarily.

 i = nil typ = nil 
+5
source

Source: https://habr.com/ru/post/1236490/


All Articles