为什么接口类型不提供“IsNil”方法? [英] Why interface type doesn't provide an "IsNil" method?

查看:296
本文介绍了为什么接口类型不提供“IsNil”方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先让我们考虑以下内容:
$ b $ pre $ func process(body io.Reader){
fmt.Printf( body == nil?%+ v \ n,body == nil)
}

func main(){
var body * bytes.Buffer
fmt.Printf(body == nil?%+ v \ n,body == nil)
process(body)
process(nil)
}

以下是输出:

  body == nil?真
正文==零?假//你有这个权利吗?
正文==零? true

另一个例子:

  type Container struct {
Reader io.Reader
}

func processContainer(container Container){
fmt.Printf(container。 Reader == nil?%+ v \ n,container.Reader == nil)
}

func main(){
var body * bytes.Buffer
processContainer(Container {Reader:body})
processContainer(Container {Reader:nil})
}

输出:

  container.Reader == nil?假//你有这个权利吗? 
container.Reader == nil?真正的

这个解释在 https://golang.org/doc/faq#nil_error



一个天真的解决方案是如果接口对象包含 nil 值,那么使 == nil test只返回true。但是这会违反 == 的传递性,因为它会在 == IsNil()方法类型,这可以解决这个问题吗?

另外一个例子,这个来自Go http客户端的线路,可以很好地捕捉到你:

https:/ /github.com/golang/go/blob/master/src/net/http/client.go#L545



所以如果你这样称呼它

  var body * bytes.Buffer 
http.NewRequest(method,path,body)
code>

即使从源代码的角度看,这也不会发生,你会得到一个零指针异常。 / p>

编辑

抱歉,我引用了Go http源的错误行,现在纠正了。
但是这个例子仍然存在。



编辑2

我已经突出了我的问题,以说明我在问什么。

首先阅读这个相关的问题:隐藏零值,理解为什么golang在这里失败



通过将接口值与 nil nil $ c $。
$ b

如果你想检查一个非 - nil 接口中的值是否为 nil ,您可以使用反射: reflect.Value.IsNil()



请参阅此修改示例:

  func process(body io.Reader){
fmt.Printf(process():body == nil?%t \\\
,正文==无)
如果body!= nil {
fmt.Println(\ tINSIDE IsNil():,reflect.ValueOf(body).IsNil())
}
}

func main(){
var body * bytes.Buffer
fmt.Printf(main():body == nil? %t $ \\ n,body == nil)
process(body)
process(nil)
process(& bytes.Buffer {})
}

输出(在 Go Playground ):

  main():body == nil ():真正的
process():body == nil?false
INSIDE IsNil():true
process():body == nil?true
process():body = = nil?false
INSIDE IsNil():false

如果你想要一个统一 IsNil()函数,它告诉是否 nil

  func IsNil(i interface {})bool {
return i == nil || reflect.ValueOf(i).IsNil()
}


First let's consider the following:

func process(body io.Reader) {
    fmt.Printf("body == nil ? %+v\n", body == nil)
}

func main() {
    var body *bytes.Buffer
    fmt.Printf("body == nil ? %+v\n", body == nil)
    process(body)
    process(nil)
}

And here's the output:

body == nil ? true
body == nil ? false  // Did you get this right?
body == nil ? true

Another example:

type Container struct {
    Reader io.Reader
}

func processContainer(container Container) {
    fmt.Printf("container.Reader == nil ? %+v\n", container.Reader == nil)
}

func main() {
    var body *bytes.Buffer
    processContainer(Container{Reader: body})
    processContainer(Container{Reader: nil})
}

Output:

container.Reader == nil ? false // Did you get this right?
container.Reader == nil ? true

The explanation for this is at https://golang.org/doc/faq#nil_error.

A naive solution is to make the == nil test just return true if the interface object contains nil value. But this would violate transitivity of ==, as it would assert two objects with nil value but different interface types true under ==.

However, I wonder if there should be an IsNil() method on all interface types, which would solve this issue?

Another example, this line from Go http client, can catch you unexpectedly:

https://github.com/golang/go/blob/master/src/net/http/client.go#L545

So if you call it like this

var body *bytes.Buffer
http.NewRequest(method, path, body)

You'll get a nil pointer exception, even though, by the look of the source code, this shouldn't happen.

Edit

Sorry I referenced the wrong line of the Go http source, now corrected. But the example still holds.

Edit 2

I've highlighted my question to make it clear what I'm asking.

解决方案

First read this related question: Hiding nil values, understanding why golang fails here

You can check if the interface value itself is nil by comparing it to nil.

If you want to check if the value wrapped inside a non-nil interface is nil, you can use reflection: reflect.Value.IsNil().

See this modified example:

func process(body io.Reader) {
    fmt.Printf("process(): body == nil ? %t\n", body == nil)
    if body != nil {
        fmt.Println("\tINSIDE IsNil():", reflect.ValueOf(body).IsNil())
    }
}

func main() {
    var body *bytes.Buffer
    fmt.Printf("main(): body == nil ? %t\n", body == nil)
    process(body)
    process(nil)
    process(&bytes.Buffer{})
}

Output (try it on the Go Playground):

main(): body == nil ? true
process(): body == nil ? false
    INSIDE IsNil(): true
process(): body == nil ? true
process(): body == nil ? false
    INSIDE IsNil(): false

If you want a "unified" IsNil() function which tells if either is nil:

func IsNil(i interface{}) bool {
    return i == nil || reflect.ValueOf(i).IsNil()
}

这篇关于为什么接口类型不提供“IsNil”方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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