英文:
Difference between a method receiver as pointer or not
问题
为什么我不需要将PrintValue()定义为指针接收器(*One),就能够打印出"hello"呢?
package main
import "fmt"
type One struct{
    a string
}
func (o *One)AssignValue(){
    o.a = "hello"
}
func (o One)PrintValue(){
    fmt.Println(o.a)
}
func main() {
    one := One{}
    one.AssignValue()
    one.PrintValue()
}
为了能够在PrintValue()函数中打印出"hello",我们不需要将其定义为指针接收器。因为在Go语言中,当我们将一个值类型的变量作为接收器时,Go会自动将其转换为对应的指针类型。所以在这个例子中,即使PrintValue()的接收器是值类型的One,我们仍然可以通过one.PrintValue()来打印出"hello"。
英文:
Why don't I have to define PrintValue() as a pointer receiver (*One) to be able to print "hello"?
package main
import "fmt"
type One struct{
    a string
}
func (o *One)AssignValue(){
    o.a = "hello"
}
func (o One)PrintValue(){
    fmt.Println(o.a)
}
func main() {
    one := One{}
    one.AssignValue()
    one.PrintValue()
}
答案1
得分: 0
因为one已经是类型One的实例。实例化语法
t := One{}
创建了一个类型为One的值,而形式
p := &One{}
创建了一个类型为One的指针。
这意味着当调用t.PrintValue时,不需要进行任何操作,因为接收器类型(One)已经与t的类型(也是One)相同。
当调用p.PrintValue时,编译器会自动将可寻址的变量转换为其指针形式,因为接收器类型(One)与p的类型(*One)不相等。因此,表达式
p.PrintValue()
被转换为
(*p).PrintValue()
当调用t.AssignValue时,也需要进行转换,因为该方法具有指针接收器,但我们提供的是一个值。在可能的情况下,编译器也会自动完成这个转换。
根据调用规范:
> 如果方法集(x的类型)包含m,并且参数列表可以分配给m的参数列表,则方法调用x.m()是有效的。如果x是可寻址的并且&x的方法集包含m,则x.m()是&x.m()的简写形式。
这意味着表达式
t.AssignValue()
被转换为
(&t).AssignValue()
请注意,这并不总是可能的。例如,在从函数返回值时:
func NewOne(s string) One { return One{s} }
NewOne("foo").AssignValue() // 不可能
x := NewOne("foo")
x.AssignValue() // 可能,自动转换
英文:
Because one is already of type One. The instantiation syntax
t := One{}
creates a value of type One while the form
p := &One{}
creates a pointer to a value of type One.
This means that nothing is to be done when calling t.PrintValue as the receiver type (One) is already the same as the type of t (One as well).
When calling p.PrintValue the compiler automatically converts an addressable variable to its pointer form because the receiver type (One) is not equal to the type of p (*One). So the expression
p.PrintValue()
is converted to
(*p).PrintValue()
There is also a conversion necessary when calling t.AssignValue as this method has a pointer receiver but we're supplying a value. This is also done automatically by the compiler where possible.
From the spec on 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()
This means the expression
t.AssignValue()
is converted to
(&t).AssignValue()
Note that this is not always possible. For example when returning a value from a function:
func NewOne(s string) One { return One{s} }
NewOne("foo").AssignValue() // Not possible
x := NewOne("foo")
x.AssignValue() // Possible, automatically converted
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论