Hallo,
Ich wollte fragen, ob es möglich ist, die Nullwerte für int
neu zu definieren. Ich brauche zum Beispiel so etwas:
...
# int32
max: 2147483647
min: -2147483648
Wenn der Wert festgelegt ist, sollte er den angegebenen Wert verwenden, und wenn kein Wert angegeben ist, sollte er den definierten Null-/Standardwert verwenden. Leider kann ich 0
nicht als Nullwert verwenden, da es sich um einen gültigen Wert für Min/Max handelt.
Meine aktuelle Lösung besteht darin, ein string
anstelle von int
zu verwenden.
Sie können einfach Standardwerte festlegen, wenn Sie einen Wert ungleich Null angeben:
type Stuff struct {
Max int32
Min int32
}
func Parse(in []byte) error {
var stuff = Stuff{Max: 2147483647, Min: -147483648}
if err := yaml.Unmarshal(in, &stuff); err != nil {
return err
}
...
return nil
}
Eine andere Option wäre die Verwendung von:
type Stuff struct {
Max *int32
Min *int32
}
Sie können dann erkennen, dass der Wert nicht eingestellt wurde, und ihn korrigieren.
Wird die erste Option tatsächlich unterstützt? Ich habe es getestet und der Wert der Eigenschaft wird auf den Standardwert seines Typs zurückgesetzt, wenn der Wert nicht in der Yaml-Datei angegeben ist.
Bearbeiten: Ich habe auch die Tests durchsucht und konnte keinen für diesen Fall finden.
@vincentbernat Tolle Tipps, ich habe mich über diese beiden Ansätze gewundert, und sie funktionieren großartig! Kleiner Tippfehler, ich glaube du brauchst ein = Zeichen:
var stuff = Stuff{Max: 2147483647, Min: -147483648} # type is infered
Danke noch einmal!
Wie machen Sie das für komplexere Strukturen, bei denen die Unterstrukturen einen Standardwert haben sollten ... ZB:
type SomeStruct struct {
A string `yaml:"a"`
Things struct {
Foo []*Stuff `yaml:"foo"`
} `yaml:"things"`
Comment string `yaml:"comment"`
}
Und wenn ich möchte, dass die Elemente im Foo-Array Standardwerte haben ...
... Es sieht so aus, als müsste ich die Unmarshaler-Schnittstelle implementieren ... https://godoc.org/gopkg.in/yaml.v2#Unmarshaler und das per Struct tun ... Daran arbeiten ...
Sie müssen UnmarshalYAML
für Stuff
implementieren:
func (s *Stuff) UnmarshalYAML(unmarshal func(interface{}) error) error {
type rawStuff Stuff
raw := rawStuff{} // Put your defaults here
if err := unmarshal(&raw); err != nil {
return err
}
*s = Stuff(raw)
return nil
}
@vincentbernat Cool...
Es scheint also Folgendes:
type rawStuff Stuff
ist im Grunde eine Umleitung zum "Schummeln" und als Ergebnis die unendliche Rekursion zu vermeiden, die ich sah, als ich den temporären "rohen" Typ nicht ersetzte ... Ist diese Analyse korrekt?
Ist das das idiomatische Muster für so etwas?
Danke noch einmal!
PS: Dies sind jetzt zwei Projekte, die ich verwende, wo ich Ihren Namen gesehen habe. Ich schätze, ich schulde dir an dieser Stelle einen Drink!
Ja, Ihre Analyse ist richtig. Ich kann nichts über den idiomatischen Teil sagen, da ich nur ein normaler Benutzer bin (und noch kein sehr erfahrener). Ich werde das Getränk jederzeit nehmen, aber ich werde es wahrscheinlich in zwei Wochen vergessen. :)
Netter Austausch. Abschließend scheinen die Fragen sortiert worden zu sein.
@niemeyer Ich würde sagen, dass dies einen Doc-Patch benötigt, bevor Sie schließen. Können Sie bitte wieder öffnen und den Titel ändern?
Wenn Sie eine klare Vorstellung davon haben, was dokumentiert werden soll, reichen Sie bitte einen Vorschlag ein.
Sie müssen
UnmarshalYAML
fürStuff
implementieren:func (s *Stuff) UnmarshalYAML(unmarshal func(interface{}) error) error { type rawStuff Stuff raw := rawStuff{} // Put your defaults here if err := unmarshal(&raw); err != nil { return err } *s = Stuff(raw) return nil }
Netter und intelligenter Trick, aber ich werde nicht funktionieren, wenn Sie eine leere Zeichenfolge an den Unmarshaller übergeben:
func main() {
unmarshalled := &speedProviderConfig{}
yamlStr := ""
err := yaml.Unmarshal([]byte(yamlStr), unmarshalled)
}
type speedProviderConfig struct {
MinimumBytesPerSeconds int64 `yaml:"min"`
MaximumBytesPerSeconds int64 `yaml:"max"`
}
func (c *speedProviderConfig) UnmarshalYAML(value *yaml.Node) error {
type rawSpeedProviderConfig speedProviderConfig // create a subtype to trick goyaml. If we where using Decode() on a speedProviderConfig it will go into an infinite recursion
conf := rawSpeedProviderConfig{
MinimumBytesPerSeconds: 5000,
MaximumBytesPerSeconds: 15000,
}
err := value.Decode(&conf)
if err != nil {
return errors.Wrapf(err, "bandwidth.speedProviderConfig: failed to unmarshall")
}
*c = speedProviderConfig(conf)
return nil
}
Die obige main()
-Funktion erzeugt einen speedProvider
-Wert von 0 und 0. Wenn der String leer ist, scheint das Umnarshalling überhaupt nicht stattzufinden, und es bedeutet auch, dass unsere Standardwerte nicht vorhanden sind einstellen.
Was ich empfehle ist:
func main() {
unmarshalled := defaultSpeedProviderConfig()
yamlStr := ""
err := yaml.Unmarshal([]byte(yamlStr), unmarshalled)
}
type speedProviderConfig struct {
MinimumBytesPerSeconds int64 `yaml:"min"`
MaximumBytesPerSeconds int64 `yaml:"max"`
}
func defaultSpeedProviderConfig() *speedProviderConfig {
return &speedProviderConfig{
MinimumBytesPerSeconds: 5000,
MaximumBytesPerSeconds: 15000,
}
}
Hilfreichster Kommentar
Sie müssen
UnmarshalYAML
fürStuff
implementieren: