在Golang中将接口设置为零 [英] Set an interface to nil in Golang
问题描述
我尝试将接口的内部值设置为零,如下所示:
typ:=& amp ; TYP {InternalState:filled}
setNil(typ)
fmt.Printf(期望%v为零,典型值)
我需要知道如何实现 setNil(typ interface {})
方法。
有关更多详情,请查看此代码play.golang.org 。
事情是你没有界面价值。你有一个指针值,一个指向具体类型的指针。这与接口值不同。
如果要更改任何类型变量的值,必须将指针传递给它。这还包括接口类型的变量以及指针类型的变量。这是非常少见的情况之一,当 interface {}
指针有意义时( * interface {}
),实际上这是不可避免的。但是,如果你的函数需要一个接口并且你传递了一个非接口值,那么一个接口值将被隐含地创建,并且你可能只有 nil
这个隐式创建的值。
所以我们有两个不同的/不同的情况:
函数至 nil
an 界面{}
func setNilIf(v * interface {}){
$ p
* v = nil
}
使用它:
var i interface {} =Bob
fmt.Printf(Before:%v \\\
,i)
setNilIf(& i)
fmt.Printf(After:%v \\\
,i)
输出:
之前:Bob
之后:< nil>
所以可以。
功能
nil
一个指针;使用不安全
其实这是你的情况。我们想要改变指针类型变量的值。要接受任何类型的指针,我们可以使用
unsafe.Pointer
。unsafe.Pointer
是语言支持,它是一种特殊的指针类型,可以从任何指针类型转换而来。
我们希望接受指针变量的地址(指针),它类似于
** SOMETYPE
。要真正能够为指针变量赋值一个新的值(nil
),我们必须对它进行反引用(*
运营商)。但是unsafe.Pointer
不能被解除引用,所以首先我们必须将它转换为指向something的指针,但是因为我们只想分配nil
(这与所有指针类型相同,无论指针值的类型如何),something无关紧要,我只需使用int
,所以我会将
unsafe.Pointer
指针值转换为** int
。 p>
func setNilPtr(p unsafe.Pointer){
*(** int)(p)= nil
}
使用它:
typ:=& TYP {InternalState:filled}
fmt.Printf(Before:%v \ n,typ)
setNilPtr(unsafe.Pointer( & typ))
fmt.Printf(After:%v \\\
,typ)
输出:
之前:& {filled}
之后:< nil>
所以这个也可以。还有另一种使用反射的方法:
函数为
nil
一个指针;使用reflect
您也可以使用
nil
仅反射(反映
包)。我们仍然需要传递指针类型变量的地址。请注意,在这种情况下,参数的类型将简单地为interface {}
。它将包含一个动态类型,如** SomeType
。由于指针的值为零nil
,我们可以通过reflect.Zero()
,我们将使用Value.Set()
:
func setNilPtr2(i interface {}){
v:= reflect.ValueOf(i)
v.Elem()。Set(reflect.Zero(v.Elem()。Type )))
}
使用它:
typ2:=& TYP {InternalState:filled}
fmt.Printf(Before:%v \ n,typ2)
setNilPtr2(& typ2)
fmt.Printf(After:%v \\\
,typ2)
输出:
之前:& {填充}
之后:< nil>
所以这个也可以。在去游乐场试试这些。
但严重:如果你想要
nil
某物,分配nil
到它。
i = nil
typ = nil
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.
解决方案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:
Function to
nil
aninterface{}
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
a pointer; usingunsafe
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). Butunsafe.Pointer
cannot be dereferenced, so first we have to convert it to a pointer to pointer to "something", but since we only want to assignnil
(which is the same to all pointer types regardless of the type of the pointed value), the "something" doesn't matter, I will just useint
, and so I will convert theunsafe.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:
Function to
nil
a pointer; usingreflect
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 beinterface{}
. And it will contain a dynamic type like**SomeType
. Since pointers have zero valuenil
, we can obtain such a value withreflect.Zero()
which we will set usingValue.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, assignnil
to it. Do not complicate things unnecessarily.i = nil typ = nil
这篇关于在Golang中将接口设置为零的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!