方法内部的指针默认会被解引用吗?

huangapple go评论91阅读模式
英文:

Are pointers dereferenced by default inside of methods?

问题

我对Go语言中的结构体方法感到困惑。我在一个教程中跟着做,他们写了以下代码:

func (p *Page) save() error {
    filename := p.Title + ".txt"
    return ioutil.WriteFile(filename, p.Body, 0600)
}

根据我的理解,p 是一个指针,如果要获取属性的话,需要对指针进行解引用,例如:

filename := (*p).Title + ".txt"

这只有在点号(.)的作用类似于C++中的->时才有意义。我错过了什么吗?

英文:

I'm confused by methods on structs in Go. I've following along in a tutorial in which they have:

func (p *Page) save() error {
    filename := p.Title + ".txt"
    return ioutil.WriteFile(filename, p.Body, 0600)
}

From my understanding, p is pointer and you would need to dereference the pointer before retrieving a property for example:

filename := (*p).Title + ".txt"

The only way this makes sense to me is if the dot is acting like -> in C++. What am I missing?

答案1

得分: 31

是的,对结构体的指针进行选择操作时,指针会自动解引用。根据选择器规范的说明:

> 以下规则适用于选择器:

> 1. 对于类型为 T*T 的值 x,其中 T 不是指针类型或接口类型,x.f 表示在 T 中最浅层的字段或方法,只要存在这样的 f。如果最浅层的深度上不止一个 f,则选择器表达式是非法的。
>
> ...
>
> 3. 作为一个例外,如果 x 的类型是一个命名的指针类型,并且 (*x).f 是一个有效的选择器表达式,表示一个字段(但不是方法),那么 x.f(*x).f 的简写形式。

因此,以下两个语句是相同的(第一个语句更常用):

filename := p.Title + ".txt"
filename := (*p).Title + ".txt"
英文:

Yes, the pointer to the struct is automatically dereferenced. From the spec on selectors:

> The following rules apply to selectors:

> 1. For a value x of type T or *T where T is not a pointer or interface type, x.f denotes the field or method at the shallowest depth in T
> where there is such an f. If there is not exactly one f with
> shallowest depth, the selector expression is illegal.
>
> ...
>
> 3. As an exception, if the type of x is a named pointer type and (*x).f is a valid selector expression denoting a field (but not a
> method), x.f is shorthand for (*x).f.

Therefore, the following two statements are the same (with the first being preferred):

filename := p.Title + ".txt"
filename := (*p).Title + ".txt"

答案2

得分: 2

在Go语言中,访问结构体的字段时不需要使用指针引用或特殊的访问操作符。

myRef := &ILikeCompositeLiteralInitilization{}
fmt.Println(myRef.Dereferenced)

与下面的代码功能上是等价的:

fmt.Println((*myRef).Dereferenced)

值得注意的是,对于函数的行为不同。也就是说,如果要调用一个接收值而不是指针的方法,我必须进行解引用。

func (*ILikeCompositeLiteralInitilization) PointerVersion()
func (ILikeCompositeLiteralInitilization) ValueVersion()

myRef.PointerVersion() // 编译器可以接受

myRef.ValueVersion() // 无法编译

(*myRef).ValueVersion() // 编译器可以接受

基本上,对于函数来说,不会发生隐式的解引用或取地址操作,因此你的代码无法编译通过。

英文:

You do not have to deference pointers or use a special access operator to access the fields of a struct in Go.

myRef := &ILikeCompositeLiteralInitilization{}
fmt.Println(myRef.Dereferenced);

is functionally equivalent to;

fmt.Printn((*myRef).Dereferenced);

Possibly worth noting that the behavior for functions is not like this. Meaning, I would have to dereference to invoke a method who's recieving type is the value and not a pointer. IE;

func (*ILikeCompositeLiteralInitilization) PointerVersion()
func (ILikeCompositeLiteralInitilization) ValueVersion()

myRef.PointerVersion() // compiler likes this

myRef.ValueVersion() // won't compile

(*myRef).ValueVersion() // compiler is OK with this

Basically, with functions no implicit dereference or address of type operation will occur, your code won't compile.

huangapple
  • 本文由 发表于 2015年6月12日 00:19:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/30786206.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定