dsfsfdsf4544 2015-11-21 09:07
浏览 126

在Golang中将接口设置为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.

  • 写回答

1条回答 默认 最新

  • douhui8163 2015-11-21 11:38
    关注

    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
    ", i)
    setNilIf(&i)
    fmt.Printf("After: %v
    ", 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
    ", typ)
    setNilPtr(unsafe.Pointer(&typ))
    fmt.Printf("After: %v
    ", 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
    ", typ2)
    setNilPtr2(&typ2)
    fmt.Printf("After: %v
    ", 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
    
    评论

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器