Esistono più risposte / tecniche alla seguente domanda:
- Come impostare i valori predefiniti per le strutture Golang?
- Come inizializzare le strutture in Golang
Ho un paio di risposte ma sono necessarie ulteriori discussioni.
Esistono più risposte / tecniche alla seguente domanda:
Ho un paio di risposte ma sono necessarie ulteriori discussioni.
Risposte:
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
}
NewSomething
e persino i campi Text
e DefaultText
, ma non esportare il tipo di struttura something
.
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.
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
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).
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.
Votes unit32
probabilmente dovrebbe essereVotes uint32
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
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
}
type Config struct {
AWSRegion string `default:"us-west-2"`
}