匿名字段作为指针或嵌入

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

Anonymous field as pointer or embed

问题

匿名字段作为指针和匿名字段作为普通字段的区别是什么?考虑一下,我如何将Foo嵌入到Bar结构体中。

看一下以下代码片段:

首先是使用匿名字段作为指针:

package main

import (
	"fmt"
)

type Foo struct{}

func (*Foo) Run() {
	fmt.Println("Hello")
}

type Bar struct {
	*Foo
}

func main() {
	bar := new(Bar)
	bar.Run()
}

然后是使用普通的匿名字段:

package main

import (
	"fmt"
)

type Foo struct{}

func (*Foo) Run() {
	fmt.Println("Hello")
}

type Bar struct {
	Foo
}

func main() {
	bar := new(Bar)
	bar.Run()
}

它们之间有什么不同?

更新:
我从revel web框架中选取了这个示例,它是如何扩展自定义控制器的。看一下这段代码:

type App struct {
	*revel.Controller
}

为什么revel使用指针来嵌入控制器结构体?这样做有什么意义?

英文:

What is the different between anonymous field as pointer or anonymous field as usual. Consider, how I embed Foo into Bar struct.

Look at the following code snippet:

First with anonymous field as pointer

package main

import (
	"fmt"
)

type Foo struct{}

func (*Foo) Run() {
	fmt.Println("Hello")
}

type Bar struct {
	*Foo
}

func main() {
	bar := new(Bar)
	bar.Run() 
}

and second anonymous field as usual:

package main

import (
	"fmt"
)

type Foo struct{}

func (*Foo) Run() {
	fmt.Println("Hello")
}

type Bar struct {
	Foo
}

func main() {
	bar := new(Bar)
	bar.Run()
}

What is different between them?

Update:
I pick up this sample from [revel webframework][1], how they extend a custom controller. Look at this code snippet

type App struct {
	*revel.Controller
}

why do revel use pointer to embed controller struct. What is the sense of it?
[1]: http://revel.github.io/tutorial/requestflow.html

答案1

得分: 6

假设Foo是一个空结构体,在Bar中嵌入它不会改变Bar的内存占用。

然而,如果将Foo嵌入为一个指针,将会改变Bar;它会添加一个指针值,并初始化为nil。如果Foo的唯一目的是拥有方法,那么使用指针是多余的。

当然,如果你在Foo中添加了一些字段,那么在指针的情况下,你还需要在主函数中添加bar.Foo = new(Foo),否则会出现问题。

使用指针的优点是你可以在多个Bar实例之间共享相同的Foo实例,或者你可以将其保持为nil,直到真正需要它。

缺点是如果始终存在一个一对一的Foo-Bar映射,那么使用指针会稍微麻烦一些,效率也会稍微降低。

英文:

Given that Foo is an empty struct, embedding it in Bar will make no change to to the memory footprint of Bar.

However, embedding a pointer to Foo will change Bar; it will add a pointer value, initialized to nil. If the only purpose of Foo is to have methods, then using a pointer is superfluous.

Of course, were you to add some fields into Foo, then, in the pointer case, you'd also need to add bar.Foo = new(Foo) into main, or else you'll have problems.

The advantage of using a pointer would be that you could share the same Foo instance between multiple instances of Bar, or else you could keep it nil until you really need it.

The disadvantage would be that it would be slightly more trouble, and slightly less efficient, if there's always a 1-to-1 Foo-to-Bar mapping.

答案2

得分: 0

只要形成有效的选择器,除了以下情况(以及使用值与指针的常规权衡之外),在使用上没有区别:

  • 如果x是指针类型且具有值nil,并且x.f表示一个结构字段,对x.f进行赋值或评估会导致运行时恐慌。
  • 如果x是接口类型且具有值nil,调用或评估方法x.f会导致运行时恐慌。

还有这个:

  • 如果S包含一个匿名字段T,则S和*S的方法集都包括接收器为T的提升方法。S的方法集还包括接收器为T的提升方法。
  • 如果S包含一个匿名字段T,则S和S的方法集都包括接收器为T或*T的提升方法。
英文:

As long as it forms valid selector there is no difference in usage except the following ( and the usual tradeoffs of using values vs. pointers ) :

> - If x is of pointer type and has the value nil and x.f denotes a struct field, assigning to or evaluating x.f causes a run-time panic.
> - If x is of interface type and has the value nil, calling or evaluating the method x.f causes a run-time panic.

and this :

> - If S contains an anonymous field T, the method sets of S and *S both
> include promoted methods with receiver T. The method set of *S also
> includes promoted methods with receiver *T.
> - If S contains an anonymous field *T, the method sets of S and *S both include promoted methods
> with receiver T or *T.

huangapple
  • 本文由 发表于 2014年9月5日 18:22:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/25683711.html
匿名

发表评论

匿名网友

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

确定