我正在学习接口,类型转换和带有指针接收器的方法。指针接收器方法背后的规则和术语使我感到困惑。让我展示我对一个程序的困惑。
这是我的Go程序。
package main import "fmt" type Employee struct { Name string } func (e Employee) Hi() { fmt.Printf("Hi! I am %s.\n", e.Name) } func (e *Employee) Hello() { fmt.Printf("Hello! I am %s.\n", e.Name) } func main() { var a Employee = Employee{"Alice"} a.Hi() a.Hello() var b interface{} = Employee{"Bob"} b.(Employee).Hi() // b.(Employee).Hello() }
这是输出。
Hi! I am Alice. Hello! I am Alice. Hi! I am Bob.
如果删除最后注释的行,则会出现此错误。
# command-line-arguments ./foo.go:24: cannot call pointer method on b.(Employee) ./foo.go:24: cannot take the address of b.(Employee)
如何修复该行代码,以便能够使用指针接收器调用该方法?请通过提出带有指针接收器的方法的概念来说明解决方案,以阐明为什么它不起作用。
您不能(在这种情况下,对于指针接收器是隐式的)获取表达式(b.(Employee))的地址。您可以获取变量的地址。例如,
b.(Employee)
package main import "fmt" type Employee struct { Name string } func (e Employee) Hi() { fmt.Printf("Hi! I am %s.\n", e.Name) } func (e *Employee) Hello() { fmt.Printf("Hello! I am %s.\n", e.Name) } func main() { var a Employee = Employee{"Alice"} a.Hi() a.Hello() var b interface{} = Employee{"Bob"} b.(Employee).Hi() // b.(Employee).Hello() // main.go:24: cannot call pointer method on b.(Employee) // main.go:24: cannot take the address of b.(Employee) e := b.(Employee) // e, a variable, is addressable e.Hello() var c interface{} = &Employee{"Chris"} c.(*Employee).Hi() c.(*Employee).Hello() }
输出:
Hi! I am Alice. Hello! I am Alice. Hi! I am Bob. Hello! I am Bob. Hi! I am Chris. Hello! I am Chris.
Go编程语言规范 类型断言 对于具有接口类型和类型T的表达式x,主要表达式 x.(T) 断言x不为nil,并且x中存储的值的类型为T。符号x。(T)称为类型断言。 如果类型断言成立,则表达式的值为存储在x中的值,其类型为T。如果类型断言为false,则会发生运行时恐慌。 来电 如果x的方法集包含m并且参数列表可以分配给m的参数列表,则方法调用xm()是有效的。如果x是可寻址的并且&x的方法集包含m,则xm()是(&x).m()的简写。 地址运算符 对于类型T的操作数x,地址操作&x生成指向 T的类型 T的指针。操作数必须是可寻址的,即变量,指针间接寻址或切片索引操作;或可寻址结构操作数的字段选择器;或可寻址数组的数组索引操作。除可寻址性要求外,x还可为(可能带有括号的)复合文字。
Go编程语言规范
类型断言
对于具有接口类型和类型T的表达式x,主要表达式
x.(T)
断言x不为nil,并且x中存储的值的类型为T。符号x。(T)称为类型断言。
如果类型断言成立,则表达式的值为存储在x中的值,其类型为T。如果类型断言为false,则会发生运行时恐慌。
来电
如果x的方法集包含m并且参数列表可以分配给m的参数列表,则方法调用xm()是有效的。如果x是可寻址的并且&x的方法集包含m,则xm()是(&x).m()的简写。
地址运算符
对于类型T的操作数x,地址操作&x生成指向 T的类型 T的指针。操作数必须是可寻址的,即变量,指针间接寻址或切片索引操作;或可寻址结构操作数的字段选择器;或可寻址数组的数组索引操作。除可寻址性要求外,x还可为(可能带有括号的)复合文字。
类型断言的值b.(Employee)是类型Employee。该方法调用b.(Employee).Hello()是速记的,(&b.(Employee)).Hello()因为它func (e *Employee) Hello()有一个指针接收器。但是,b.(Employee)表达式不能寻址。因此,
Employee
b.(Employee).Hello()
(&b.(Employee)).Hello()
func (e *Employee) Hello()
error: cannot call pointer method on b.(Employee) error: cannot take the address of b.(Employee)