Come impostare i valori predefiniti nelle strutture Go


143

Esistono più risposte / tecniche alla seguente domanda:

  1. Come impostare i valori predefiniti per le strutture Golang?
  2. Come inizializzare le strutture in Golang

Ho un paio di risposte ma sono necessarie ulteriori discussioni.



@icza La tua risposta fornisce un modo per farlo ma andando dal titolo della domanda, non è in alcun modo simile o ricercabile poiché è una domanda molto specifica. Aggiungerò il link nella mia risposta però.
Prateek,

Ci sono due domande qui, scegline una. Supponendo di optare per la prima domanda (come da titolo della domanda), si prega di essere più specifici sulla ricerca precedente e in cui le altre risposte richiedono più discussioni.
Duncan Jones,

Risposte:


96

Un'idea possibile è scrivere una funzione di costruzione separata

//Something is the structure we work with
type Something struct {
     Text string 
     DefaultText string 
} 
// NewSomething create new instance of Something
func NewSomething(text string) Something {
   something := Something{}
   something.Text = text
   something.DefaultText = "default text"
   return something
}

6
Sì, questo è uno dei modi che ho menzionato anche nella mia risposta, ma non è possibile forzare nessuno a utilizzare solo questa funzione.
Prateek,

@Prateek è o questo o usa un'interfaccia, che sarebbe brutta e complicata.
OneOfOne,

31
@Prateek sì, puoi forzare le persone a usare questo costruttore se rendi il tipo stesso non esportato. È possibile esportare la funzione NewSomethinge persino i campi Texte DefaultText, ma non esportare il tipo di struttura something.
Amit Kumar Gupta,

1
Il problema è peggiore ... se una terza parte (libreria, ad esempio) viene utilizzata per istanziare la struttura (tramite reflect.New(), ad esempio), non ci si può aspettare che conoscano la funzione di fabbrica con un nome speciale. In quel caso, e a parte la lingua stessa che viene cambiata, solo un'interfaccia (che la biblioteca potrebbe verificare) farebbe, penso.
edam,

1
È utile impostare il valore predefinito, ma a volte potrei voler sostituire il valore predefinito. In questo caso, non sarò in grado di inizializzare una struttura con un valore non predefinito. un po 'fastidioso per me
Juliatzin,

68
  1. Forzare un metodo per ottenere la struttura (il modo costruttore).

    Un buon progetto è rendere il tuo tipo non esportato, ma fornire una funzione di costruzione esportata come NewMyType () in cui puoi inizializzare correttamente la tua struttura / tipo. Restituisce anche un tipo di interfaccia e non un tipo concreto e l'interfaccia dovrebbe contenere tutto ciò che gli altri vogliono fare con il tuo valore. E il tuo tipo concreto deve implementare quell'interfaccia ovviamente.

    Questo può essere fatto semplicemente rendendo il tipo stesso non esportato. Puoi esportare la funzione NewSomething e persino i campi Text e DefaultText, ma non esportare qualcosa del tipo struct

  2. Un altro modo per personalizzarlo per il proprio modulo consiste nell'utilizzare una struttura di configurazione per impostare i valori predefiniti (opzione 5 nel collegamento).



3
È disponibile nella macchina di ritorno .
n8henrie,

FWIW, penso che sia "Opzione 3" - almeno nel collegamento macchina di ritorno. (Non c'è 'Opzione 5', lì).
decimus phostle

@ m90 per mettere a tacere Golint puoi dichiarare la tua funzione come restituzione del tipo di interfaccia pubblica
Thomas Grainger

@ThomasGrainger Il mio commento sembra riferirsi a una precedente revisione di questa risposta, non ha più senso in questo modo :) Lo eliminerò.
m90,

32

Un problema con l'opzione 1 in risposta di Victor Zamanian è che se il tipo non viene esportato, gli utenti del pacchetto non possono dichiararlo come tipo per i parametri della funzione ecc. Un modo per aggirare questo sarebbe esportare un'interfaccia anziché il struct ad es

package candidate
// Exporting interface instead of struct
type Candidate interface {}
// Struct is not exported
type candidate struct {
    Name string
    Votes uint32 // Defaults to 0
}
// We are forced to call the constructor to get an instance of candidate
func New(name string) Candidate {
    return candidate{name, 0}  // enforce the default value here
}

Ciò ci consente di dichiarare i tipi di parametri di funzione utilizzando l'interfaccia Candidate esportata. L'unico svantaggio che posso vedere da questa soluzione è che tutti i nostri metodi devono essere dichiarati nella definizione dell'interfaccia, ma si potrebbe sostenere che questa è comunque una buona pratica.


è disponibile per modificare la variabile Nome e Voti dopo la chiamata Nuova funzione?
morteza khadem,

Bel semplice esempio.

piccolo errore di battitura: Votes unit32probabilmente dovrebbe essereVotes uint32
PartyLich

@PartyLich ben individuato. Dovrebbe essere risolto.
wolfson109,

13

C'è un modo per farlo con i tag, che consente impostazioni predefinite multiple.

Si supponga di avere il seguente struct, con le etichette predefinite 2 DEFAULT0 e Default1 .

type A struct {
   I int    `default0:"3" default1:"42"`
   S string `default0:"Some String..." default1:"Some Other String..."`
}

Ora è possibile impostare le impostazioni predefinite.

func main() {

ptr := &A{}

Set(ptr, "default0")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=3 ptr.S=Some String...

Set(ptr, "default1")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=42 ptr.S=Some Other String...
}

Ecco il programma completo in un parco giochi .

Se sei interessato a un esempio più complesso, ad esempio con sezioni e mappe, dai un'occhiata a creasty / defaultse


Molte grazie! Ho iniziato a scrivere lo stesso codice suggerito dalla libreria e mi sono imbattuto in questo post. Fa esattamente quello che ti aspetti ( github.com/creasty/defaults ). Se non hai alcun valore, imposta il valore predefinito, ma se hai assegnato un valore alla tua variabile, non assegnerà il valore predefinito. Funziona abbastanza bene con la libreria yaml.v2.
Nordes,

3

Da https://golang.org/doc/effective_go.html#composite_literals :

A volte il valore zero non è abbastanza buono ed è necessario un costruttore di inizializzazione, come in questo esempio derivato dal pacchetto operativo.

    func NewFile(fd int, name string) *File {
      if fd < 0 {
        return nil
      }
      f := new(File)
      f.fd = fd
      f.name = name
      f.dirinfo = nil
      f.nepipe = 0
      return f
}

-3
type Config struct {
    AWSRegion                               string `default:"us-west-2"`
}

1
Questo non è corretto Nella migliore delle ipotesi, potresti impostare un valore di tag su quel campo e poi arrivare al suo valore con la riflessione ma anche con questo la sintassi è errata (mancano i segni di spunta) e potresti solo impostare un valore predefinito per un tipo di stringa. Se hai qualche idea su cosa si riferisca specificamente a questo esempio, aggiungi un link a cui fare riferimento.
markeissler,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.