Istnieje wiele odpowiedzi / technik na poniższe pytanie:
- Jak ustawić domyślne wartości struktur golang?
- Jak zainicjować struktury w golang
Mam kilka odpowiedzi, ale wymagana jest dalsza dyskusja.
Istnieje wiele odpowiedzi / technik na poniższe pytanie:
Mam kilka odpowiedzi, ale wymagana jest dalsza dyskusja.
Odpowiedzi:
Jednym z możliwych pomysłów jest napisanie oddzielnej funkcji konstruktora
//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
a nawet pola Text
i DefaultText
, ale po prostu nie eksportuj typu struktury something
.
reflect.New()
na przykład przez), nie można oczekiwać, że dowie się o twojej specjalnie nazwanej funkcji fabryki. W takim przypadku, poza zmianą samego języka, wystarczyłby tylko interfejs (który biblioteka mogłaby sprawdzić).
Wymuś metodę, aby uzyskać strukturę (sposób konstruktora).
Dobrym projektem jest niewyeksportowanie typu, ale zapewnienie wyeksportowanej funkcji konstruktora, takiej jak NewMyType (), w której można poprawnie zainicjować strukturę / typ. Zwróć także typ interfejsu, a nie konkretny typ, a interfejs powinien zawierać wszystko, co inni chcą zrobić z twoją wartością. Twój konkretny typ musi oczywiście implementować ten interfejs.
Można to zrobić, po prostu wyłączając sam typ. Możesz wyeksportować funkcję NewSomething a nawet pola Text i DefaultText, ale po prostu nie eksportuj struktury wpisz coś
Innym sposobem dostosowania go do własnego modułu jest użycie struktury Config do ustawienia wartości domyślnych (opcja 5 w linku). Nie jest to jednak dobry sposób.
Jednym z problemów z opcją 1 w odpowiedzi Victora Zamaniana jest to, że jeśli typ nie jest eksportowany, użytkownicy twojego pakietu nie mogą zadeklarować go jako typ parametrów funkcji itp. Jednym ze sposobów obejścia tego byłoby wyeksportowanie interfejsu zamiast struktura np
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
}
Dzięki temu możemy zadeklarować typy parametrów funkcji za pomocą wyeksportowanego interfejsu Kandydata. Jedyną wadą, jaką widzę w tym rozwiązaniu, jest to, że wszystkie nasze metody muszą być zadeklarowane w definicji interfejsu, ale można by argumentować, że i tak jest to dobra praktyka.
Votes unit32
prawdopodobnie powinno byćVotes uint32
Można to zrobić za pomocą tagów, które pozwalają na wiele wartości domyślnych.
Załóżmy, że masz następującą strukturę z 2 domyślnymi tagami default0 i default1 .
type A struct {
I int `default0:"3" default1:"42"`
S string `default0:"Some String..." default1:"Some Other String..."`
}
Teraz można ustawić wartości domyślne.
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...
}
Oto pełny program na placu zabaw .
Jeśli interesuje Cię bardziej złożony przykład, powiedzmy z plasterkami i mapami, spójrz na creasty / defaultse
Z https://golang.org/doc/effective_go.html#composite_literals :
Czasami wartość zero nie jest wystarczająco dobra i potrzebny jest konstruktor inicjujący, jak w tym przykładzie pochodzącym z pakietu os.
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"`
}