英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论