dpjjr42626 2017-05-10 14:46
浏览 41
已采纳

为什么接口类型不提供“ IsNil”方法?

First let's consider the following:

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

func main() {
    var body *bytes.Buffer
    fmt.Printf("body == nil ? %+v
", 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
", 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.

  • 写回答

1条回答 默认 最新

  • douxi8119 2017-05-10 15:00
    关注

    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
    ", 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
    ", 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()
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 jupyterthemes 设置完毕后没有效果
  • ¥15 matlab图像高斯低通滤波
  • ¥15 针对曲面部件的制孔路径规划,大家有什么思路吗
  • ¥15 钢筋实图交点识别,机器视觉代码
  • ¥15 如何在Linux系统中,但是在window系统上idea里面可以正常运行?(相关搜索:jar包)
  • ¥50 400g qsfp 光模块iphy方案
  • ¥15 两块ADC0804用proteus仿真时,出现异常
  • ¥15 关于风控系统,如何去选择
  • ¥15 这款软件是什么?需要能满足我的需求
  • ¥15 SpringSecurityOauth2登陆前后request不一致