如何在类型断言后调用带指针接收器的方法?

时间:2017-05-10 04:19:18

标签: pointers go interface type-conversion

我正在使用指针接收器学习接口,类型转换和方法。 指针接收器方法背后的规则和术语让我感到困惑。 让我向一个程序表明我的困惑。

这是我的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)

如何修复该行代码,以便我能够调用该方法 指针接收器?请解释一个解决方案,并澄清为什么会这样 通过使用指针接收器设置方法的概念不起作用。

2 个答案:

答案 0 :(得分:4)

您不能(在这种情况下隐含地用于指针接收器)获取表达式(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.
  

The Go Programming Language Specification

     

Type assertions

     

对于接口类型的表达式x和类型T,表示主要的   表达

x.(T)
     

断言x不是nil,并且存储在x中的值是T类型。   符号x。(T)称为类型断言。

     

如果类型断言成立,则表达式的值为值   存储在x中,其类型为T.如果类型断言为false,则a   发生运行时恐慌。

     

Calls

     

方法调用x.m()在方法集(类型)x时有效   包含m,参数列表可以分配给参数列表   米如果x是可寻址的并且& x的方法集包含m,则x.m()是   (& x).m()

的简写      

Address operators

     

对于类型为T的操作数x,地址操作& x生成a   类型* T到x的指针。操作数必须是可寻址的,即   变量,指针间接或切片索引操作;   或可寻址结构操作数的字段选择器;或数组   可寻址数组的索引操作。作为例外   可寻址性要求,x也可以是(可能括在括号中)   复合文字。

类型断言b.(Employee)的值属于Employee类型。方法调用b.(Employee).Hello()(&b.(Employee)).Hello()的简写,因为func (e *Employee) Hello()具有指针接收器。但是,b.(Employee),一个表达式,是不可寻址的。因此,

error: cannot call pointer method on b.(Employee)
error: cannot take the address of b.(Employee)

答案 1 :(得分:-2)

修复将是:

var b interface{} = &Employee{"Bob"}
b.(*Employee).Hello()

这里的b是一个实际上是“指向Employee的指针”的接口,然后是类型断言的接口。要记住的是“员工”和“员工指针”是两种不同的类型。