英文:
How to invoke a method with pointer receiver after type assertion?
问题
我正在学习接口、类型转换和带指针接收器的方法。
指针接收器方法的规则和术语对我来说很困惑。
让我用一个程序来展示我的困惑。
这是我的 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)
如何修复这行代码,以便能够调用带有指针接收器的方法?请解释一种解决方案,并对为什么这样做不起作用的概念进行一些澄清。
英文:
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.
答案1
得分: 7
在这种情况下(隐式地针对指针接收器),你不能获取表达式(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, 一个变量,是可寻址的
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.
在这里,类型断言 b.(Employee)
的值是类型 Employee
。方法调用 b.(Employee).Hello()
是 (&b.(Employee)).Hello()
的简写,因为 func (e *Employee) Hello()
有一个指针接收器。但是,表达式 b.(Employee)
是不可寻址的。因此,
错误:无法在 b.(Employee) 上调用指针方法
错误:无法获取 b.(Employee) 的地址
英文:
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)
答案2
得分: -1
修复方法如下:
var b interface{} = &Employee{"Bob"}
b.(*Employee).Hello()
这里的b是一个实际上是"指向Employee的指针"的接口,然后进行了类型断言。需要记住的是,"Employee"和"指向Employee的指针"是两种完全不同的类型。
英文:
The fix would be:
var b interface{} = &Employee{"Bob"}
b.(*Employee).Hello()
Here b is an interface that is actually a "pointer to Employee" and then same has been type asserted. The thing to remember is that "Employee" and "pointer to Employee" are two different types altogether.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论