【问题标题】:Set an interface to nil in Golang在 Golang 中将接口设置为 nil
【发布时间】:2016-02-23 19:45:21
【问题描述】:

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

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

fmt.Printf("Expecting that %v to be nil", typ)

而且我需要知道如何实现setNil(typ interface{}) 方法。

更多详情see this code in play.golang.org。

【问题讨论】:

  • 但是为什么呢?你能不使用布尔值吗?
  • @yene:我喜欢让我的界面设计更简洁。
  • 如果不直接从函数返回nil,我看不出它是如何完成的。例如,想想setNil(3)。

标签: pointers go reflection interface


【解决方案1】:

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

如果你想改变任何类型的变量的值,你必须传递一个指向它的指针。这也包括接口类型的变量,以及指针类型的变量。这是指向 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

【讨论】:

  • 谢谢 icza ,但我不想让我的客户知道 unsafe.Pointer ,而且我不希望我的客户将类型传递为 *interface{}。那么你能做到吗?=> play.golang.org/p/KhR4-BHMPW
  • @Mohsen 查看已编辑的答案。我添加了第三种方式,仅在函数内部使用反射。必须要传递变量的地址,这是无法避免的,但是这个没有使用unsafe.Pointer。
  • :非常感谢 icza,但我必须,看看:play.golang.org/p/aPslX_vgiJ(为什么没有通用!):-)
猜你喜欢
  • 2015-07-21
  • 1970-01-01
  • 2017-10-11
  • 2016-10-12
  • 2023-04-08
  • 2020-01-06
  • 2010-12-13
  • 1970-01-01
  • 2011-09-01
相关资源
最近更新 更多