Constructoras en Go


Tengo una estructura y me gustaría inicializarla con algunos valores predeterminados sensibles.

Normalmente, lo que hay que hacer aquí es usar un constructor, pero como go no es realmente OOP en el sentido tradicional, estos no son objetos verdaderos y no tiene constructores.

He notado el método init pero eso está en el nivel del paquete. ¿Hay algo similar que se pueda usar a nivel de estructura?

Si no, cuál es la mejor práctica aceptada para este tipo de cosas ¿en Go?

Author: Flimzy, 2013-08-08

8 answers

En realidad hay dos buenas prácticas aceptadas:

  1. Haga que el valor cero de su estructura sea un valor predeterminado razonable. (Si bien esto parece extraño para la mayoría de las personas que vienen de" tradicional " oop a menudo funciona y es muy conveniente).
  2. Proporcione una función func New() YourTyp o si tiene varios de estos tipos en su paquete functions func NewYourType1() YourType1 y así sucesivamente.

Documento si un valor cero de su tipo es utilizable o no (en cuyo caso tiene que ser configurado por una de las funciones New.... (Para el "tradicionalista" oops: Alguien que no lea la documentación no podrá usar sus tipos correctamente, incluso si no puede crear objetos en estados indefinidos.)

 95
Author: Volker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-08 12:14:23

Hay algunos equivalentes de constructores para cuando los valores cero no pueden hacer valores por defecto sensibles o para cuando algún parámetro es necesario para la inicialización de la estructura.

Supongamos que tienes una estructura como esta:

type Thing struct {
    Name  string
    Num   int
}

Entonces, si los valores cero no encajan, normalmente construiría una instancia con una función NewThing que devuelve un puntero:

func NewThing(someParameter string) *Thing {
    p := new(Thing)
    p.Name = someParameter
    p.Num = 33 // <- a very sensible default value
    return p
}

Cuando su estructura es lo suficientemente simple, puede usar esta construcción condensada :

func NewThing(someParameter string) *Thing {
    return &Thing{someParameter, 33}
}

Si no quiere devolver un puntero, entonces una práctica es llamar a la función makeThing en lugar de NewThing:

func makeThing(name string) Thing {
    return Thing{name, 33}
}

Referencia : Asignación con nuevo en Efectivo Go.

 139
Author: Denys Séguret,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-11 07:19:10

Go tiene objetos. Los objetos pueden tener constructores (aunque no constructores automáticos). Y finalmente, Go es un lenguaje OOP (los tipos de datos tienen métodos adjuntos, pero hay un sinfín de definiciones de lo que es OOP.)

Sin embargo, la mejor práctica aceptada es escribir cero o más constructores para sus tipos.

Como @dystroy publicó su respuesta antes de terminar esta respuesta, permítanme agregar una versión alternativa de su constructor de ejemplo, que probablemente escribe en su lugar como:

func NewThing(someParameter string) *Thing {
    return &Thing{someParameter, 33} // <- 33: a very sensible default value
}

La razón por la que quiero mostrarte esta versión es que muy a menudo se pueden usar literales "en línea" en lugar de una llamada "constructor".

a := NewThing("foo")
b := &Thing{"foo", 33}

Ahora *a == *b.

 24
Author: zzzz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-13 17:57:19

No hay constructores predeterminados en Go, pero puede declarar métodos para cualquier tipo. Podrías convertirlo en un hábito declarar un método llamado "Init". No estoy seguro de cómo se relaciona esto con las mejores prácticas, pero ayuda a mantener los nombres cortos sin perder claridad.

package main

import "fmt"

type Thing struct {
    Name string
    Num int
}

func (t *Thing) Init(name string, num int) {
    t.Name = name
    t.Num = num
}

func main() {
    t := new(Thing)
    t.Init("Hello", 5)
    fmt.Printf("%s: %d\n", t.Name, t.Num)
}

El resultado es:

Hello: 5
 7
Author: Sebastian Bartos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-30 16:01:03

Otra forma es;

package person

type Person struct {
    Name string
    Old  int
}

func New(name string, old int) *Person {
    // set only specific field value with field key
    return &Person{
        Name: name,
    }
}
 3
Author: K-Gun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-26 20:14:35

Me gusta la explicación de esta entrada de blog :

La función New es una convención Go para paquetes que crean un tipo core o tipos diferentes para su uso por el desarrollador de la aplicación. Observe cómo se define e implementa New en log.vaya, bufio.ve y cypto.go:

Tronco.go

// New creates a new Logger. The out variable sets the
// destination to which log data will be written.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
func New(out io.Writer, prefix string, flag int) * Logger {
    return &Logger{out: out, prefix: prefix, flag: flag}
}

Bufio.go

// NewReader returns a new Reader whose buffer has the default size.
func NewReader(rd io.Reader) * Reader {
    return NewReaderSize(rd, defaultBufSize)
}

Cripto.go

// New returns a new hash.Hash calculating the given hash function. New panics
// if the hash function is not linked into the binary.
func (h Hash) New() hash.Hash {
    if h > 0 && h < maxHash {
        f := hashes[h]
        if f != nil {
            return f()
        }
    }
    panic("crypto: requested hash function is unavailable")
}

Dado que cada paquete actúa como un espacio de nombres, cada paquete puede tener su propio versión de Nuevo. En bufio.se pueden crear varios tipos, por lo que no hay una Nueva función independiente. Aquí encontrarás funciones como NewReader y NewWriter.

 1
Author: Ivan Aracki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-15 22:19:24

Golang no es lenguaje OOP en sus documentos oficiales. Todos los campos de la estructura de Golang tienen un valor determinado (no como c / c++), por lo que la función constructora no es tan necesaria como cpp. Si necesita asignar algunos campos algunos valores especiales, utilice las funciones de fábrica. La comunidad de Golang sugiere Algo Nuevo.. nombres de patrones.

 0
Author: hurricane1026,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-11 06:51:04

Si quieres emular la sintaxis de ___.new() puedes hacer algo como:

type Thing struct {
    Name string
    Num int
}
type Constructor_Thing struct {}
func (c CThing) new(<<CONSTRUCTOR ARGS>>) Thing {
  var thing Thing
  //initiate thing from constructor args
  return thing
}
var cThing CThing

func main(){
  var myThing Thing
  myThing = cThing.new(<<CONSTRUCTOR ARGS>>)
  //...
}

Concedido, es una pena que Thing.new() no se pueda implementar sin CThing.new() que también se implemente (iirc), lo que es un poco una vergüenza...

 -1
Author: Sancarn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-21 09:35:54