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