我试图将接口的内部值设置为nil
,如下所示:
typ := &TYP{InternalState: "filled"}
setNil(typ)
fmt.Printf("Expecting that %v to be nil", typ)
我需要知道如何实现setNil(typ interface{})
方法。
答案 0 :(得分:6)
问题是你没有接口值。你有一个指针值,一个指向具体类型的指针。这与界面值不同。
如果要更改任何类型变量的值,则必须将指针传递给它。这还包括接口类型的变量,以及指针类型的变量。当指向interface{}
的指针有意义时(*interface{}
),这是非常罕见的情况之一,实际上它是不可避免的。
但是如果你的函数需要一个接口而你传递一个非接口值,那么将隐式创建一个接口值,你只能nil
这个隐式创建的值。
所以我们有2个不同/不同的案例:
nil
和interface{}
func setNilIf(v *interface{}) {
*v = nil
}
使用它:
var i interface{} = "Bob"
fmt.Printf("Before: %v\n", i)
setNilIf(&i)
fmt.Printf("After: %v\n", i)
输出:
Before: Bob
After: <nil>
所以它有效。
nil
指针的功能;使用unsafe
实际上这是你的情况。我们想要改变指针类型变量的值。要接受指向任何类型的指针,我们可以使用unsafe.Pointer
。 unsafe.Pointer
是language support,它是一种特殊的指针类型,可以从任何指针类型转换为。
我们希望接受指针变量的地址(指针),类似于**SomeType
。要实际能够为指针变量分配新值(nil
),我们必须取消引用它(*
运算符)。但是unsafe.Pointer
不能被解除引用,所以首先我们必须将它转换为指向“某事”的指针,但是因为我们只想分配nil
(这与所有指针类型相同,不管指向值的类型),“某事”无关紧要,我将只使用int
,因此我将unsafe.Pointer
指针值转换为**int
。
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\n", 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: %v\n", typ2)
setNilPtr2(&typ2)
fmt.Printf("After: %v\n", typ2)
输出:
Before: &{filled}
After: <nil>
所以这个也行。请在Go Playground上尝试这些。
但严重的是:如果您想要nil
某事,请为其指定nil
。不要不必要地使事情复杂化。
i = nil
typ = nil