在Golang中将接口设置为nil

Moh*_*sen 5 reflection pointers interface go

我正在尝试将接口的内部值设置nil为如下所示:

typ := &TYP{InternalState: "filled"}
setNil(typ)

fmt.Printf("Expecting that %v to be nil", typ)
Run Code Online (Sandbox Code Playgroud)

我需要知道如何实现该setNil(typ interface{})方法.

有关更多详细信息,请参阅play.golang.org中的此代码.

icz*_*cza 6

问题是你没有接口值.你有一个指针值,一个指向具体类型的指针.这与界面值不同.

如果要更改任何类型的变量的值,则必须将指针传递给它.这还包括接口类型的变量,以及指针类型的变量.当指针变为interface{}有意义(*interface{})时,这是非常罕见的情况之一,实际上它是不可避免的.

但是,如果您的函数需要接口并且传递非接口值,则将隐nil式创建接口值,并且您只能隐式创建该值.

所以我们有2个不同/不同的案例:

功能到nilinterface{}

func setNilIf(v *interface{}) {
    *v = nil
}
Run Code Online (Sandbox Code Playgroud)

使用它:

var i interface{} = "Bob"
fmt.Printf("Before: %v\n", i)
setNilIf(&i)
fmt.Printf("After: %v\n", i)
Run Code Online (Sandbox Code Playgroud)

输出:

Before: Bob
After: <nil>
Run Code Online (Sandbox Code Playgroud)

所以它有效.

函数nil指针; 运用unsafe

其实这是你的情况.我们想要改变指针类型变量的值.要接受指向任何类型的指针,我们可以使用unsafe.Pointer.unsafe.Pointer是一种语言支持,它是一种特殊的指针类型,可以从任何指针类型转换.

我们想接受指针变量的地址(指针),就像这样**SomeType.为了能够为nil指针变量分配新的值(),我们必须取消引用它(*运算符).但是unsafe.Pointer不能被解除引用,所以首先我们必须将它转换为指向"某事"的指针,但由于我们只想分配nil(对于所有指针类型都是相同的,无论指向的值的类型如何)," "无关紧要,我将使用int,所以我将unsafe.Pointer指针值转换为**int.

func setNilPtr(p unsafe.Pointer) {
    *(**int)(p) = nil
}
Run Code Online (Sandbox Code Playgroud)

使用它:

typ := &TYP{InternalState: "filled"}
fmt.Printf("Before: %v\n", typ)
setNilPtr(unsafe.Pointer(&typ))
fmt.Printf("After: %v\n", typ)
Run Code Online (Sandbox Code Playgroud)

输出:

Before: &{filled}
After: <nil>
Run Code Online (Sandbox Code Playgroud)

所以这一个也有效.还有另一种使用反射的方法:

函数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()))
}
Run Code Online (Sandbox Code Playgroud)

使用它:

typ2 := &TYP{InternalState: "filled"}
fmt.Printf("Before: %v\n", typ2)
setNilPtr2(&typ2)
fmt.Printf("After: %v\n", typ2)
Run Code Online (Sandbox Code Playgroud)

输出:

Before: &{filled}
After: <nil>
Run Code Online (Sandbox Code Playgroud)

所以这一个也有效.在Go Playground尝试这些.


但是严肃地说:如果你想要nil什么,请分配nil给它.不要不必要地使事情复杂化.

i = nil
typ = nil
Run Code Online (Sandbox Code Playgroud)