在Golang中将接口设置为零 [英] Set an interface to nil in Golang

查看:220
本文介绍了在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 {}){
* 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 an interface{}

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; using unsafe

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). But unsafe.Pointer cannot be dereferenced, so first we have to convert it to a pointer to pointer to "something", but since we only want to assign nil (which is the same to all pointer types regardless of the type of the pointed value), the "something" doesn't matter, I will just use int, and so I will convert the unsafe.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; using reflect

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 be interface{}. And it will contain a dynamic type like **SomeType. Since pointers have zero value nil, we can obtain such a value with reflect.Zero() which we will set using Value.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, assign nil to it. Do not complicate things unnecessarily.

i = nil
typ = nil

这篇关于在Golang中将接口设置为零的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆