事实上,您没有接口值。您有一个指针值,指向具体类型的指针。这与接口值不同。
如果要更改任何类型变量的值,则必须传递一个指向它的指针。这也包括接口类型的变量,以及指针类型的变量。这是非常罕见的情况之一,需要使用指向
interface{}
的指针(
*interface{}
),事实上是不可避免的。
但是,如果您的函数期望一个接口,并且您传递一个非接口值,则将隐式创建一个接口值,并且您只能将其设置为
nil
。
因此,我们有两种不同/独立的情况:
将
interface{}
设置为
nil
的功能
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>
所以这样就可以了。
使用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: %v\n", typ)
setNilPtr(unsafe.Pointer(&typ))
fmt.Printf("After: %v\n", typ)
输出:
Before: &{filled}
After: <nil>
这种方式同样有效。还有一种使用反射的方法来使指针为nil
:
使用 reflect
函数使指针为 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\n", typ2)
输出:
Before: &{filled}
After: <nil>
这个也可以运行。请在Go Playground上尝试。
但是认真地说:如果你想将某物设为nil
,只需将其赋值为nil
。不要不必要地复杂化问题。
i = nil
typ = nil
nil
,该怎么做。例如,考虑一下setNil(3)
。 - julienc