【问题标题】:Embedding in Go with pointer or with value用指针或值嵌入 Go
【发布时间】:2015-04-14 15:14:45
【问题描述】:

我可以在 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
}

指针和值更喜欢什么?

【问题讨论】:

标签: go


【解决方案1】:

这取决于。这里有几种可能性。

  • 如果 Renderer 是按值传递的,并且您需要在 Bitmap 上使用的方法在 *Bitmap 上定义,那么您需要嵌入 *Bitmap。
  • 如果 Renderer 作为指针传递,那么您可以毫无问题地将 Bitmap 作为值嵌入(在这种情况下仍然可以访问指针方法)。
  • 如果 Bitmap 具有返回指针的构造函数,并且 Bitmap 的零值不可用,则需要嵌入 *Bitmap,因为您不希望鼓励按值复制 Bitmap 值.
  • 如果所有的Bitmap方法都是值方法,那你肯定要按值嵌入。

在您在这里的特定情况下,我可能会按值嵌入,因为类型很小 - 它为您提供访问的局部性和更少的内存分配。

【讨论】:

    【解决方案2】:

    通过嵌入您通常希望从呼叫转移中受益的类型。 *Bitmap's method setBitmap's method set 的超集。所以在大多数情况下,你会想要嵌入*Bitmap,除非它的所有方法都有Bitmap 类型的接收器,或者方法将它设置为空,在这种情况下你可以避免间接。

    【讨论】:

      【解决方案3】:

      我试过了: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
      

      【讨论】:

      • 你的代码的重点是如果你定义了一个值接收器setter函数,它不能改变传入的值。改变或不改变与指针或值嵌入有关
      【解决方案4】:

      正如罗格的回答所表达的那样,似乎对接收者存在误解。方法(接收者)没有“定义”在指针或类型上,可以在类型值上调用与指针相同的方法,接收者的签名仅确定它接收的是类型值还是指向的指针类型的值。也就是说func(t *YourType) 可以在YourType&YourType 上调用,反之亦然。我认为这应该澄清:https://play.golang.org/p/AT1J2oGkum 至于是否嵌入值或指针的问题......引用性实际上取决于您如何处理外部对象,如果您将指针传递给外部结构,您将可以访问相同的嵌入结构值,如果您要传递外部结构的值,您希望它指向嵌入结构的“原始”基础值还是副本?我认为在大多数情况下,您要么想要嵌入一个指针并将指针传递给您的外部结构,要么嵌入一个值并传递您的外部结构的值。

      【讨论】:

        【解决方案5】:

        我还发现,当您有多个结构都具有相同的嵌入式基本类型,并且您想要使用修改基本结构的值的辅助函数时,它很有用。例如,给定以下结构:

        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)
        

        【讨论】:

          猜你喜欢
          • 2017-08-12
          • 1970-01-01
          • 1970-01-01
          • 2016-07-12
          • 1970-01-01
          • 2021-12-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多