我正在尝试将接口的内部值设置为nil
,如下所示:
typ := &TYP{InternalState: "filled"}
setNil(typ)
fmt.Printf("Expecting that %v to be nil", typ)
我需要知道如何实现setNil(typ interface{})
方法。
有关更多详细信息,请参阅play.golang.org.
问题是您没有接口值。您有一个指针值,一个指向具体类型的指针。这与接口值不同。
如果你想更改任何类型的变量的值,你必须向它传递一个指针。这也包括接口类型的变量,也包括指针类型的变量。当指向interface{}
的指针有意义(*interface{}
)时,这是非常罕见的情况之一,事实上这是不可避免的。
但是,如果您的函数需要一个接口,而您传递了一个非接口值,则会隐式创建一个接口值,并且您只能nil
这个隐式创建的值。
因此,我们有两种不同/不同的情况:
nil
和interface{}
的函数
func setNilIf(v *interface{}) {
*v = nil
}
使用它:
var i interface{} = "Bob"
fmt.Printf("Before: %vn", i)
setNilIf(&i)
fmt.Printf("After: %vn", i)
输出:
Before: Bob
After: <nil>
所以它是有效的。
函数为nil
一个指针;使用unsafe
事实上这就是你的情况。我们想要更改指针类型的变量的值。要接受指向任何类型的指针,我们可以使用unsafe.Pointer
。unsafe.Pointer
是一种语言支持,它是一种特殊的指针类型,可以从任何指针类型转换为任何指针类型。
我们想要接受指针变量的地址(指针),它类似于**SomeType
。为了实际能够为指针变量分配一个新值(nil
),我们必须取消引用它(*
运算符)。但是unsafe.Pointer
不能被取消引用,所以首先我们必须将其转换为指向"某物"的指针,但由于我们只想分配nil
(无论所指值的类型如何,所有指针类型都相同),"某物"无关紧要,我只会使用int
,所以我会将unsafe.Pointer
指针值转换为**int
。
func setNilPtr(p unsafe.Pointer) {
*(**int)(p) = nil
}
使用它:
typ := &TYP{InternalState: "filled"}
fmt.Printf("Before: %vn", typ)
setNilPtr(unsafe.Pointer(&typ))
fmt.Printf("After: %vn", typ)
输出:
Before: &{filled}
After: <nil>
所以这个也是有效的。还有另一种使用反射的方法:
函数为nil
一个指针;使用reflect
您也可以仅使用反射来nil
指针(reflect
包)。我们仍然需要传递指针类型的变量的地址。注意,在这种情况下,参数的类型将简单地为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: %vn", typ2)
setNilPtr2(&typ2)
fmt.Printf("After: %vn", typ2)
输出:
Before: &{filled}
After: <nil>
所以这个也是有效的。在围棋场上试试这些。
但说真的:如果你想nil
,就给它分配nil
。不要让事情变得不必要的复杂。
i = nil
typ = nil