英文:
Embedding in Go with pointer or with value
问题
我可以使用指针和值在 Golang 中进行嵌入。
使用指针:
type Bitmap struct{
data [4][4]bool
}
type Renderer struct{
*Bitmap
on uint8
off uint8
}
使用值:
type Bitmap struct{
data [4][4]bool
}
type Renderer struct{
Bitmap
on uint8
off uint8
}
指针和值哪个更好,取决于具体情况。使用指针可以避免在复制大型结构体时产生额外的开销,但需要注意处理空指针的情况。使用值则更简单,不需要担心空指针的问题。根据你的需求和性能要求,选择适合的方式。
英文:
I can embed in golang with pointer and value.
By pointer
type Bitmap struct{
data [4][4]bool
}
type Renderer struct{
*Bitmap
on uint8
off uint8
}
By value
type Bitmap struct{
data [4][4]bool
}
type Renderer struct{
Bitmap
on uint8
off uint8
}
What is more prefer by pointer or value?
答案1
得分: 50
这取决于情况。这里有几种可能性:
- 如果Renderer是按值传递的,并且你需要在Bitmap上定义的方法,那么你需要嵌入Bitmap。
- 如果Renderer作为指针传递,那么你可以将Bitmap作为值嵌入,没有任何问题(在这种情况下,指针方法仍然可以访问)。
- 如果Bitmap有一个返回指针的构造函数,并且Bitmap的零值不可用,那么你应该嵌入*Bitmap,因为你不希望鼓励按值复制Bitmap值。
- 如果所有的Bitmap方法都是值方法,那么你肯定希望按值嵌入。
在你这里的具体情况中,我可能会选择按值嵌入,因为这种类型很小 - 它可以提供访问的局部性和更少的内存分配。
英文:
It depends. There are several possibilities here.
- If Renderer is passed around by value and the methods you need on Bitmap are defined on *Bitmap, then you'll need to embed *Bitmap.
- If Renderer is passed around as a pointer, then you can embed Bitmap as a value without any problem (pointer methods will still be accessible in this case).
- If Bitmap has a constructor function that returns a pointer, and the zero value of Bitmap isn't usable, you'll want to embed *Bitmap, as you don't want to encourage by-value copying of the Bitmap value.
- If all the Bitmap methods are value methods, then you definitely want to embed by value.
In the specific case you have here, I'd probably embed by value, as the type is small - it gives you locality of access and less memory allocations.
答案2
得分: 15
通过嵌入一个类型,通常你希望从调用转发中受益。*Bitmap
的set方法是Bitmap
的set方法的超集。所以在大多数情况下,你会想要嵌入*Bitmap
,除非它的所有方法都有一个类型为Bitmap
的接收器,或者方法集为空,这种情况下你可以避免间接引用。
英文:
By embedding a type you usually want to benefit from call-forwarding. *Bitmap
's method set is a super set of Bitmap
's method set. So in most cases you'll want to embed *Bitmap
, unless all its methods have a receiver of type Bitmap
or the method set it empty, in which cases you can avoid the indirection.
答案3
得分: 10
在rog的回答中,对接收者存在误解。方法(接收者)并不是“定义在”指针或类型上的,相同的方法可以在类型的值和指针上调用,接收者的签名只决定它接收值类型还是指向值类型的指针。也就是说,func(t *YourType)
可以在YourType
或&YourType
上调用,反之亦然,使用值接收者。我认为这应该能澄清问题:https://play.golang.org/p/AT1J2oGkum
至于嵌入值还是指针的问题...引用性实际上取决于你如何处理外部对象,如果你传递一个指向外部结构体的指针,你将可以访问相同的嵌入结构体值,如果你传递外部结构体的值,你想让它指向嵌入结构体的“原始”底层值还是一个副本?我认为在大多数情况下,你要么想嵌入一个指针并传递指向外部结构体的指针,要么嵌入一个值并传递外部结构体的值。
英文:
There seems so be a misunderstanding of receivers, as expressed in rog's answer. Methods (receivers) are not "defined on" a pointer or a type, the same methods can be called on the value-of-type as the pointer, the receiver's signature only determines whether it receives value-of-type or a pointer to value-of-type. That is to say func(t *YourType)
can be called on YourType
or &YourType
and vice-versa with a value receiver. I think this should clarify: https://play.golang.org/p/AT1J2oGkum
So as to the question as to whether to embed a value or pointer...the referentiality is really determined by how you deal with the outer object, if you are passing a pointer to the outer struct you will have access to the same embedded struct value, if you are passing the value of the outer struct, do you want it to point to the "original" underlying value of the embedded struct or a copy? I think in most cases you will either want to embed a pointer and pass pointers to your outer struct, or embed a value and pass value of your outer struct.
答案4
得分: 8
我试过了:https://play.golang.org/p/IVM5OoDU9ZN
package main
import (
"fmt"
)
type Base struct {
Name string
}
func (b Base) PrintName() {
fmt.Println(b.Name)
}
func (b *Base) PrintNameP() {
fmt.Println(b.Name)
}
func (b Base) ChangeName(name string) {
b.Name = name
}
func (b *Base) ChangeNameP(name string) {
b.Name = name
}
type EmbedsBase struct {
Base
}
type EmbedsPointerToBase struct {
*Base
}
func main() {
fmt.Println("")
fmt.Println("# embed by value and refrenced by value, not change origianl value")
b := Base{"Jeff Hardy"}
eb := EmbedsBase{b}
eb.PrintName()
eb.ChangeName("John Cena")
eb.PrintName()
fmt.Println("")
fmt.Println("# embed by value, but refrenced by pointer, changed origianl value")
b = Base{"Jeff Hardy"}
ebp := &EmbedsBase{b}
ebp.PrintNameP()
ebp.ChangeNameP("John Cena")
ebp.PrintNameP()
fmt.Println("")
fmt.Println("# embed by pointer, but refrenced by value, not chage origianl value")
b = Base{"Jeff Hardy"}
epb := EmbedsPointerToBase{&b}
epb.PrintName()
epb.ChangeName("John Cena")
epb.PrintName()
fmt.Println("")
fmt.Println("# embed by pointer, and refrenced by pointer, changed origianl value")
b = Base{"Jeff Hardy"}
epbp := &EmbedsPointerToBase{&b}
epbp.PrintNameP()
epbp.ChangeNameP("John Cena")
epbp.PrintNameP()
}
以上的结果是:
# embed by value and refrenced by value, not change origianl value
Jeff Hardy
Jeff Hardy
# embed by value, but refrenced by pointer, changed origianl value
Jeff Hardy
John Cena
# embed by pointer, but refrenced by value, not chage origianl value
Jeff Hardy
Jeff Hardy
# embed by pointer, and refrenced by pointer, changed origianl value
Jeff Hardy
John Cena
英文:
i tried: https://play.golang.org/p/IVM5OoDU9ZN
package main
import (
"fmt"
)
type Base struct {
Name string
}
func (b Base) PrintName() {
fmt.Println(b.Name)
}
func (b *Base) PrintNameP() {
fmt.Println(b.Name)
}
func (b Base) ChangeName(name string) {
b.Name = name
}
func (b *Base) ChangeNameP(name string) {
b.Name = name
}
type EmbedsBase struct {
Base
}
type EmbedsPointerToBase struct {
*Base
}
func main() {
fmt.Println("")
fmt.Println("# embed by value and refrenced by value, not change origianl value")
b := Base{"Jeff Hardy"}
eb := EmbedsBase{b}
eb.PrintName()
eb.ChangeName("John Cena")
eb.PrintName()
fmt.Println("")
fmt.Println("# embed by value, but refrenced by pointer, changed origianl value")
b = Base{"Jeff Hardy"}
ebp := &EmbedsBase{b}
ebp.PrintNameP()
ebp.ChangeNameP("John Cena")
ebp.PrintNameP()
fmt.Println("")
fmt.Println("# embed by pointer, but refrenced by value, not chage origianl value")
b = Base{"Jeff Hardy"}
epb := EmbedsPointerToBase{&b}
epb.PrintName()
epb.ChangeName("John Cena")
epb.PrintName()
fmt.Println("")
fmt.Println("# embed by pointer, and refrenced by pointer, changed origianl value")
b = Base{"Jeff Hardy"}
epbp := &EmbedsPointerToBase{&b}
epbp.PrintNameP()
epbp.ChangeNameP("John Cena")
epbp.PrintNameP()
}
the result of above is:
# embed by value and refrenced by value, not change origianl value
Jeff Hardy
Jeff Hardy
# embed by value, but refrenced by pointer, changed origianl value
Jeff Hardy
John Cena
# embed by pointer, but refrenced by value, not chage origianl value
Jeff Hardy
Jeff Hardy
# embed by pointer, and refrenced by pointer, changed origianl value
Jeff Hardy
John Cena
答案5
得分: 1
我也发现当你有多个具有相同嵌入基类型的结构体,并且你想要使用一个修改基本结构体值的辅助函数时,这种方法非常有用。例如,给定以下结构体:
type Base struct {
F1 int
}
type A struct {
*Base
Fa int
}
type B struct {
*Base
Fb int
}
以及以下辅助函数:
func modstruct(base *Base) {
base.F1 = 2
}
所有以下函数调用都将编译,并修改结构体的值:
base := &Base{}
a := &A{Base: &Base{}}
b := &B{Base: &Base{}}
modstruct(base)
modstruct(a.Base)
modstruct(b.Base)
英文:
I've also found it useful when you have multiple structs all with the same embedded base type, and you want to use a helper function which modifies the values of the base struct. For example, given the following structs:
type Base struct {
F1 int
}
type A struct {
*Base
Fa int
}
type B struct {
*Base
Fb int
}
and the following helper function:
func modstruct(base *Base) {
base.F1 = 2
}
all of the following function calls will compile, and modify values of the struct:
base := &Base{}
a := &A{Base: &Base{}}
b := &B{Base: &Base{}}
modstruct(base)
modstruct(a.Base)
modstruct(b.Base)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论