如何在类型断言后使用指针接收器调用方法? [英] How to invoke a method with pointer receiver after type assertion?

查看:100
本文介绍了如何在类型断言后使用指针接收器调用方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



这是我的Go程序。

  package main 

导入fmt

类型Employee结构{
名称字符串
}

func(e Employee)Hi(){
fmt.Printf(嗨!我是%s.\\\
,e.Name)
}

func(e * Employee)Hello(){
fmt.Printf(Hello!I am%s.\\\
,e.Name)
}

func main (){
var a Employee = Employee {Alice}
a.Hi()
a.Hello()

var b interface {} = Employee {Bob}
b。(Employee).Hi()
// b。(Employee).Hello()
}

这是输出。

 嗨!我是爱丽丝。 
您好!我是爱丽丝。
嗨!我是鲍勃。

如果我删除了最后一条注释掉的行,则会出现此错误。

 #命令行参数
./foo.go:24:无法在b。(Employee)
上调用指针方法。 /foo.go:24:不能取b的地址(员工)

如何解决该行代码,以便我能够调用具有
指针接收器的方法?请解释一个解决方案,并澄清一下为什么这个
不能通过使用指针接收器来定义方法的概念。 解决方案

你不能(在这种情况下隐式指向一个指针接收者)取一个表达式结果的地址( b。(Employee))。你可以取一个变量的地址。例如,

 包主

导入fmt

类型Employee struct {
Name string
}

func(e Employee)Hi(){
fmt.Printf(嗨!我是%s.\\\
,e.Name)
}

func(e * Employee)Hello(){
fmt.Printf(Hello!I am%s.\\\
, 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:无法调用b上的指针方法(Employee)
// main.go:24:不能取b的地址(Employee)
e := b。(Employee)// e,一个变量,可寻址
e.Hello()

var c interface {} =& Employee {Chris}
*。(* Employee).Hi()
c。(* Employee).Hello()
}

输出:

 嗨!我是爱丽丝。 
您好!我是爱丽丝。
嗨!我是鲍勃。
您好!我是鲍勃。
嗨!我是克里斯。
您好!我是克里斯。







The Go Programming Language Specification

类型断言



对于接口类型的表达式x和一个T型的主要
表达式

  x。(T)

声明x不为零,并且存储在x中的值为T类型。
称为x。(T)一个类型断言。如果类型断言成立,则表达式的值是存储在x中的值
,并且其类型是T.如果类型断言是假的,则a
运行时发生恐慌。



调用



如果(x)类型的
的方法集包含m和参数列表,则方法调用xm可以分配给m的参数列表
。如果x是可寻址的并且& x的方法集包含m,则xm()是
(& x).m()的简写形式(b)

地址运算符



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

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

 错误:无法调用b上的指针方法(Employee)
错误:无法取得b的地址。(员工)


I am learning interface, type conversions and methods with pointer receivers. The rules and terminology behind pointer receiver methods are confusing to me. Let me demonstrate my confusion with one program.

This is my Go program.

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()
}

This is the output.

Hi! I am Alice.
Hello! I am Alice.
Hi! I am Bob.

If I remove the last commented out line, I get this error.

# command-line-arguments
./foo.go:24: cannot call pointer method on b.(Employee)
./foo.go:24: cannot take the address of b.(Employee)

How can I fix that line of code so that I am able to invoke the method with pointer receiver? Please explain a solution with some clarification on why this does not work by laying down the concepts of methods with pointer receiver.

解决方案

You can't (in this case implicitly for a pointer receiver) take the address of the result of an expression (b.(Employee)). You can take the address of a variable. For example,

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()
}

Output:

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

For an expression x of interface type and a type T, the primary expression

x.(T)

asserts that x is not nil and that the value stored in x is of type T. The notation x.(T) is called a type assertion.

If the type assertion holds, the value of the expression is the value stored in x and its type is T. If the type assertion is false, a run-time panic occurs.

Calls

A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m. If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m()

Address operators

For an operand x of type T, the address operation &x generates a pointer of type *T to x. The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal.

The value of the type assertion b.(Employee) is of type Employee. The method call b.(Employee).Hello() is shorthand for (&b.(Employee)).Hello() since func (e *Employee) Hello() has a pointer receiver. But, b.(Employee), an expression, is not addressable. Therefore,

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

这篇关于如何在类型断言后使用指针接收器调用方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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