tag recommendation moz metadescription length descriptions description go

go - recommendation - tag meta description



Incrustar en Go con puntero o con valor (5)

Al incrustar un tipo, normalmente desea beneficiarse del reenvío de llamadas. *Bitmap El conjunto de métodos de *Bitmap es un super conjunto del conjunto de métodos de Bitmap . Por lo tanto, en la mayoría de los casos, querrá incrustar *Bitmap , a menos que todos sus métodos tengan un receptor de tipo Bitmap o el método lo haya dejado en blanco, en cuyo caso puede evitar la indirección.

Puedo incrustar en Golang con puntero y valor. Por puntero

type Bitmap struct{ data [4][4]bool } type Renderer struct{ *Bitmap on uint8 off uint8 }

Por valor

type Bitmap struct{ data [4][4]bool } type Renderer struct{ Bitmap on uint8 off uint8 }

¿Qué es más preferir por puntero o valor?


Depende. Hay varias posibilidades aquí.

  • Si el procesador pasa el valor y los métodos que necesita en Bitmap están definidos en * Bitmap, entonces deberá incrustar * Bitmap.
  • Si el Renderer se transmite como un puntero, entonces puede incrustar Bitmap como un valor sin ningún problema (en este caso, los métodos de punteros aún serán accesibles).
  • Si Bitmap tiene una función constructora que devuelve un puntero, y el valor cero de Bitmap no se puede utilizar, querrá incrustar * Bitmap, ya que no desea alentar la copia por valor del valor de Bitmap.
  • Si todos los métodos de mapa de bits son métodos de valor, entonces definitivamente desea incrustar por valor.

En el caso específico que tiene aquí, probablemente lo incrustaría por valor, ya que el tipo es pequeño: le da una ubicación de acceso y menos asignaciones de memoria.


Lo intenté: 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() }

El resultado de arriba es:

# 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


Parece que hay una mala interpretación de los receptores, como se expresa en la respuesta de Rog. Los métodos (receptores) no están "definidos en" un puntero o un tipo, los mismos métodos pueden llamarse en el valor de tipo que el puntero, la firma del receptor solo determina si recibe un valor de tipo o un puntero para valor de tipo Es decir, se puede llamar a func(t *YourType) en YourType o &YourType y viceversa con un receptor de valores. Creo que esto debería aclarar: https://play.golang.org/p/AT1J2oGkum En lo que https://play.golang.org/p/AT1J2oGkum a la pregunta de si incrustar un valor o un puntero ... la referencia es realmente determinada por la forma en que tratas con el objeto externo, si está pasando un puntero a la estructura externa, tendrá acceso al mismo valor de estructura incrustada, si está pasando el valor de la estructura externa, ¿desea que apunte al valor subyacente "original" de la estructura incrustada o ¿una copia? Creo que en la mayoría de los casos querrá incrustar un puntero y pasar punteros a su estructura externa, o incrustar un valor y pasar el valor de su estructura externa.


También me ha resultado útil cuando tiene varias estructuras, todas con el mismo tipo de base incorporada, y desea utilizar una función auxiliar que modifique los valores de la estructura base. Por ejemplo, dadas las siguientes estructuras:

type Base struct { F1 int } type A struct { *Base Fa int } type B struct { *Base Fb int }

y la siguiente función auxiliar:

func modstruct(base *Base) { base.F1 = 2 }

Todas las siguientes llamadas a funciones compilarán y modificarán los valores de la estructura:

base := &Base{} a := &A{Base: &Base{}} b := &B{Base: &Base{}} modstruct(base) modstruct(a.Base) modstruct(b.Base)