在struct元素上调用一个函数,该函数是一个无指针指针

时间:2019-03-08 22:20:46

标签: go struct

但是,在Go语言中,Expression.Name()语法要调用的函数完全由表达式的类型决定,而不是由该表达式的特定运行时值决定,包括nil-copied

因此我们可以使用nil的struct实例调用method

考虑以下程序:

 package main

    import "fmt"

    type T struct {
        V int
        tt *T
    }

    func (t *T) hello() string {
       return "world"
   } 

    func main() {
        var t *T = nil
        fmt.Println(t, t.hello()) // <nil> world
        fmt.Println(t, t.tt.hello()) // panic
    }

fmt.Println(t, t.hello())为什么起作用?

但是

fmt.Println(t, t.tt.hello())感到惊慌?

我的理解是tt.tt都是nil指针。因此t.tt.hello()不应惊慌,因为golang中允许在nil struct指针上调用方法。

4 个答案:

答案 0 :(得分:3)

准确地说,t是nil指针,t.tt根本不存在。您看到的恐慌是取消引用t而不是t.tt的结果。 t.tt也是(或者如果初始化t也是指针)这一事实也掩盖了这一点。

可以通过访问V的{​​{1}}字段来使其更加清楚:

t

第一次测试不会出现恐慌的原因是,在func (t *T) foo() { fmt.Println(t.V) // Will panic, if `t` is nil } 上调用方法实际上并未取消引用t。调用t与调用t.Hello()大致相同,因此除非/直到在函数中实际取消引用Hello(t),否则不会惊慌。

答案 1 :(得分:2)

  

我的理解是t和t.tt都是nil指针。所以   t.tt.hello()不应惊慌,因为在nil结构上调用方法   golang中允许使用指针。

您的“理解”是错误的。t.tt应该并且确实panic


  

Go 1.2 Release Notes (December 2013)

     

Use of nil

     

出于安全原因,该语言现在规定,   确保nil个指针会触发运行时恐慌。例如,   在Go 1.0中,给定的代码如

type T struct {
    X [1<<24]byte
    Field int32
}

func main() {
    var x *T
    ...
}
     

nil指针x可能用于错误地访问内存:   表达式x.Field可以访问地址1 << 24的内存。阻止   这种不安全的行为,在Go 1.2中,编译器现在保证   通过nil指针进行间接访问,例如此处所示   在nil指向数组的指针,nil接口值,nil切片等中   开启时,将会恐慌或返回正确的安全非零值。在   简短的,任何显式或隐式要求的表达式   评估一个零地址是一个错误。实施可能会注入   对编译的程序进行额外的测试以强制执行此行为。

     

更多详细信息在design document中。


  

简而言之,任何显式或隐式要求的表达式   评估零地址是错误的。

因此,预期以下行为。通过t.tt的{​​{1}}值对nil进行的间接操作失败,并显示t

panic

游乐场:https://play.golang.org/p/Szwx5MqNHkQ

输出:

package main

import "fmt"

type T struct {
    V  int
    tt *T
}

func (t *T) hello() string {
    return "world"
}

type A struct {
    a int
}

func main() {
    var t *T = nil
    fmt.Println(t)            // nil
    fmt.Println(t.tt.hello()) // panic
}

答案 2 :(得分:2)

t为nil,没有t.tt

t.hello()就像hello(t)hello(nil)不会惊慌,但t.tt会惊慌。

Remember: a method is just a function with a receiver argument.

Method expressions

答案 3 :(得分:-1)

nil是指针的零值

// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice type

来源:https://golang.org/src/builtin/builtin.go?h=nil#L101

要了解nil,该视频太棒了
https://www.youtube.com/watch?v=ynoY2xz-F8s