Menu

Golang const: typisierte und untypisierte Konstanten erklärt

So funktioniert const in Go: Konstanten deklarieren, der Unterschied zwischen typisierten und untypisierten Konstanten, konstante Ausdrücke mit beliebiger Genauigkeit und warum Go keine konstanten Slices, Maps oder Structs hat.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

Eine Konstante ist ein Wert, der zur Compilezeit feststeht. Du deklarierst sie mit const, und Go verweigert jeden Versuch, sie zu ändern.

Konstanten können auf Paketebene oder in einer Funktion deklariert werden, eine pro Zeile oder gruppiert in einem Block const ( ... ). MB und GB werden aus anderen Konstanten berechnet, und der Compiler erledigt diese Rechnung einmal beim Build.

Eine Zuweisung an eine Konstante, etwa MaxRetries = 5, ist ein Compilerfehler:

./main.go:8:2: cannot assign to MaxRetries (neither addressable nor a map index expression)

Was eine Konstante sein kann

Nur drei Arten von Werten: Booleans, Zahlen (Ganzzahlen, Floats, komplexe Zahlen und Runes) und Strings. Der Compiler muss den Wert berechnen können, also Literale, andere Konstanten, Arithmetik darauf und ein paar eingebaute Funktionen wie len eines konstanten Strings.

Alles, was Code ausführen oder Speicher anlegen muss, fällt raus:

const Colors = []string{"red", "green"} // slice
const Started = time.Now()              // function call
./main.go:9:16: []string{…} (value of type []string) is not constant
./main.go:10:13: time.Now() (value of struct type time.Time) is not constant

Warum Go keine konstanten Slices oder Maps hat

Slices, Maps und Structs, die sie enthalten, sind Verweise auf Speicher, der zur Laufzeit existiert. Der Compiler kann sie also nicht als feste Werte ins Programm einbacken, und Go hat keine Modifikatoren wie readonly oder final für Variablen. Die üblichen Workarounds:

Die Kopie kostet pro Aufruf eine Allokation, was für Daten in Konfigurationsgröße in Ordnung ist. Für Lookups per Schlüssel ist ein switch in einer Funktion eine weitere konstantenähnliche Option: func statusText(code int) string { switch code { ... } }.

Untypisierte Konstanten

Eine Konstante, die ohne Typ deklariert ist, ist untypisiert. Sie hat eine Art (Ganzzahl, Float, Rune, String, bool), aber keinen bestimmten Go-Typ, bis sie verwendet wird, und passt sich an den Kontext an:

Ratio funktioniert ohne Konvertierung als int, float64, uint8 und float32. Deshalb kompiliert time.Sleep(2 * time.Second): 2 ist untypisiert und wird zu einer time.Duration.

Verlangt der Kontext keinen Typ, wie bei x := Ratio, bekommt die Konstante ihren Standardtyp:

Art der untypisierten KonstanteStandardtyp
Ganzzahl (42)int
Gleitkommazahl (4.2)float64
Rune ('a')rune (int32)
komplex (2i)complex128
Stringstring
Booleanbool

Exakte Arithmetik

Untypisierte numerische Konstanten sind exakt. Der Compiler stellt Ganzzahlen mit mindestens 256 Bit dar, also dürfen Zwischenwerte weit größer sein als jeder Go-Typ:

Huge selbst lässt sich nicht als Ganzzahl ausgeben, weil die Übergabe an fmt.Println sie in ein int konvertiert, und das fängt der Compiler ab (float64(Huge) funktioniert, da ein Float diese Größenordnung fassen kann):

cannot use Huge (untyped int constant 1267650600228229401496703205376) as int value in argument to fmt.Println (overflows)

Dieselbe Prüfung stoppt kleinere Fehler zur Compilezeit, etwa var b byte = 300:

cannot use 300 (untyped int constant) as byte value in variable declaration (overflows)

Typisierte Konstanten

Gibst du einer Konstanten einen Typ, verhält sie sich überall wie ein Wert dieses Typs, einschließlich der Weigerung von Go, Typen zu mischen:

const Limit int = 10

var f float64 = 2
fmt.Println(Limit * f)
invalid operation: Limit * f (mismatched types int and float64)

Mit const Limit = 10 (untypisiert) kompiliert Limit * f und ergibt 20. Lass Konstanten also untypisiert, außer der Typ trägt Bedeutung. Das tut er, wenn du Konstanten eines eigenen benannten Typs deklarierst, und so baut Go Enums:

type Weekday int

const (
	Sunday Weekday = iota
	Monday
	Tuesday
)

Hier ist der Typ der Punkt: Eine Funktion, die ein Weekday nimmt, dokumentiert, was sie will. iota und die darauf aufbauenden Enum-Muster behandelt die Seite zu Enums und iota.

const vs var

constvar
Kann sich ändernneinja
Wert bekanntzur Compilezeitzur Laufzeit
Erlaubte Typenbool, numerisch, stringbeliebig
Belegt Speicher zur Laufzeitneinja
Adresse abrufbar (&x)neinja
Ungenutzt ist ein Fehlerneinja, bei lokalen

Nimm const für alles, was wirklich feststeht: Limits, Größen, Namen, Protokollcodes, Format-Strings. Overflow-Prüfungen zur Compilezeit und exakte Arithmetik bekommst du gratis dazu.

Stolperfallen

Typisierte Konstanten passen sich nicht an. const Timeout int = 5 kann ohne Konvertierung nicht übergeben werden, wo eine time.Duration erwartet wird; ein untypisiertes const Timeout = 5 lässt sich multiplizieren: Timeout * time.Second.

Ganzzahldivision bei ganzzahligen Konstanten. const Half = 1 / 2 ist 0, weil beide Operanden untypisierte Ganzzahlen sind. Schreib 1.0 / 2, um 0.5 zu bekommen.

Keine Adresse. &MaxRetries kompiliert nicht. Will eine API ein *int, kopier die Konstante vorher in eine Variable.

Häufig gestellte Fragen

Wie deklariert man eine Konstante in Go?

Mit const: const MaxRetries = 3 oder, mit explizitem Typ, const Timeout time.Duration = 5 * time.Second. Mehrere fasst du in einem Block zusammen: const ( A = 1; B = 2 ). Der Wert muss zur Compilezeit berechenbar sein.

Kann ich in Go einen konstanten Slice, eine Map oder ein Array anlegen?

Nein. Konstanten können nur Booleans, Zahlen (einschließlich Runes) und Strings sein. const Colors = []string{"red"} scheitert mit is not constant. Nimm ein var auf Paketebene, und wenn Aufrufer es nicht ändern dürfen, biete eine Funktion an, die jedes Mal eine neue Kopie zurückgibt.

Was ist eine untypisierte Konstante in Go?

Eine Konstante, die ohne Typ deklariert ist, etwa const Pi = 3.14159. Sie hat keinen festen Typ, bis sie verwendet wird, also funktioniert dieselbe Konstante als float32, als float64 oder, wenn ihr Wert es erlaubt, als int. Untypisierte Konstanten sind außerdem exakt: Der Compiler rechnet mit mindestens 256 Bit Genauigkeit, also ist const Big = 1 << 100 erlaubt, solange du sie nur in Ausdrücken verwendest, deren Ergebnis passt.

Was ist der Unterschied zwischen const und var in Go?

Eine const steht zur Compilezeit fest und kann sich nie ändern; sie belegt zur Laufzeit keinen Speicher und kann nur ein bool, eine Zahl oder einen String enthalten. Eine var ist ein Speicherort, der neu zugewiesen werden kann und jeden Typ enthalten kann, auch Werte, die erst zur Laufzeit berechnet werden, wie time.Now().

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S