Menu

Zero Let-Bindings: Werten mit let einen Namen geben

Wie let in Zero funktioniert: lokale Bindings deklarieren, Typinferenz und explizite Annotationen, und warum Zero mit einer einzigen Binding-Form statt vieler Schlüsselwörter auskommt.

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

Ein Weg, einem Wert einen Namen zu geben

In Zero gibst du einem Wert mit let einen Namen:

let answer = 42

Das ist die ganze Syntax. Kein var, kein const, kein auto. Ein einziges Binding-Schlüsselwort hält die Sprache klein – Agenten und Menschen lernen es einmal und wenden es überall an.

let führt ein lokales Binding im aktuellen Scope ein. Nach dieser Zeile verweist answer bis zum Ende des umschließenden Blocks auf 42.

Typinferenz

Der Compiler inferiert den Typ aus der rechten Seite. Das Literal 42 hat per Default Typ i32, also ist answer ein i32. Das Literal "hello" ist ein String, also:

let greeting = "hello"

bindet greeting an einen String-Wert. Wenn du eine Funktion aufrufst, die ein Pair<i32, u8> zurückgibt, hat das Binding den Typ Pair<i32, u8>:

let pair = makePair(40, 2_u8)

Du musst nicht an jedes Binding den Typ schreiben, was den Code lesbar hält.

Explizite Typannotationen

Wenn du den Typ dokumentieren willst – oder einen bestimmten erzwingen, wenn die Inferenz etwas anderes wählen würde – schreib den Typ nach einem Doppelpunkt:

let count: u8 = 10
let pair:  Pair<i32, u8> = makePair(40, 2_u8)

Annotationen sind außerdem ein Hinweis für den Compiler, wenn ein Literal mehrere Typen haben könnte. Das Literal 10 könnte i32, i64, u8 und so weiter sein; die Annotation legt es fest.

Du wirst auch typisierte Suffixe an Literalen sehen, als Alternative zum Annotieren des Bindings:

let small = 10_u8   // u8 durch das Literal-Suffix
let big   = 10_i64  // i64 durch das Literal-Suffix

Beide Formen sind gültig; nimm die, die die Absicht an der Aufrufstelle klarer macht.

Bindings in Aktion

Ein durchgespieltes Beispiel mit inferierter und expliziter Form – klick Run, um es auszuprobieren:

point ist explizit annotiert, weil die rechte Seite ein Struct-Literal ist. total ist inferiert – sum ist als Rückgabe i32 deklariert, also ist auch das Binding i32.

Scope und Shadowing

Ein let-Binding gilt von der Zeile, die es deklariert, bis zum Ende seines umschließenden Blocks. Verschachtelte Blöcke schaffen neue Scopes:

pub fun main(world: World) -> Void raises {
    let value = 1
    if true {
        let value = 2   // überdeckt das äußere 'value' innerhalb dieses Blocks
        // hier ist value == 2
    }
    // außerhalb des if ist value wieder == 1
}

Das innere value mutiert das äußere nicht – es ist ein eigenes Binding, das beim schließenden } des if-Blocks aus dem Scope läuft. Dasselbe Modell wie in Rust und ML-artigen Sprachen. Besonders praktisch, wenn du einen Wert in einer Folge von Schritten transformieren willst, ohne für jedes Zwischenergebnis einen neuen Namen zu erfinden.

Was let nicht macht

Ein paar Dinge, die du aus anderen Sprachen erwarten könntest, die let bewusst nicht enthält:

  • Reine Typdeklarationen. Es gibt keine Form let x: i32;, die ein uninitialisiertes Binding einführt. Ein Binding muss an der Stelle, an der es deklariert wird, einen Wert haben.
  • Pattern-Destrukturierung (noch nicht). Manche Sprachen erlauben let (a, b) = pair. Zero ist bewusst klein und konzentriert sich derzeit auf reine Namens-Bindings – schau in die aktuelle Doku, ob Destrukturierung schon gelandet ist.
  • Mehrere Schlüsselwörter für unterschiedliche Lebensdauern. Kein eigenes static, const, let mut oder Varianten für Block- vs. Funktions-Scope. Ein Schlüsselwort.

Wenn dein Sprachhintergrund JavaScript ist, ist die nächste Entsprechung const – ein Name, der für den Rest des Blocks an einen Wert gebunden ist, mit Shadowing in inneren Scopes. Kommst du aus Rust, übernimmt let hier dieselbe Rolle wie Rusts let ohne das explizite mut-Schlüsselwort.

Ein Muster: einen Wert Schritt für Schritt aufbauen

Bindings glänzen, wenn du eine Berechnung als Folge benannter Zwischenschritte schreiben willst. Das ist gut für Menschen, die lesen, und für Agenten, die lokal über jede Zeile nachdenken:

Jede Zeile führt eine neue Tatsache ein, mit der der Rest der Funktion arbeiten kann. Der Compiler erzeugt trotzdem kompakten Code – Zwischenwerten Namen zu geben kostet zur Laufzeit nichts.

Als Nächstes: Primitive Typen

let ist wenig wert, ohne dass es etwas zu binden gibt. Das nächste Dokument geht durch Zeros primitive Typen – die Integer-Breiten, Floats, Strings sowie die Typen Void und Bool, die du am häufigsten sehen wirst.

Häufig gestellte Fragen

Wie deklariere ich eine Variable in Zero?

Verwende let. Die Form ist let name = wert für einen inferierten Typ oder let name: Typ = wert, um den Typ explizit anzugeben. Zum Beispiel: let answer = 42 oder let answer: i32 = 42. Beides bindet den Namen answer im aktuellen Scope an den Wert 42.

Inferiert Zero die Typen von Let-Bindings?

Ja. Schreibst du let total = sum(point) und sum gibt i32 zurück, wird der Bindings-Typ als i32 inferiert. Du kannst explizit annotieren, wenn du den Typ dokumentieren oder einen bestimmten erzwingen willst – zum Beispiel let count: u8 = 10.

Sind Let-Bindings in Zero veränderlich?

Ein einfaches let führt ein lokales Binding für seinen Scope ein. Die Mutability-Geschichte in pre-1.0 Zero entwickelt sich noch – die Sprache legt Wert auf explizite Effekte und vorhersagbaren Speicher, also muss alles, was Zustand über ein Binding verändert, das sichtbar machen. Sieh in der aktuellen Zero-Doku nach der genauen Mutability-Syntax deiner Toolchain-Version.

Was ist der Unterschied zwischen let und const in Zero?

Zero verwendet let für ganz normale lokale Bindings innerhalb von Funktions-Bodies. Es gibt keine mehreren Binding-Schlüsselwörter wie JavaScripts let/const/var – die Oberfläche klein zu halten ist eine bewusste Designentscheidung. Compile-Zeit-Konstanten werden typischerweise über das Typsystem oder Top-Level-Deklarationen ausgedrückt, nicht über ein eigenes Schlüsselwort.

Kann man ein Let-Binding in Zero erneut deklarieren?

Bindings leben in ihrem umschließenden Scope. Ein neues let mit demselben Namen in einem verschachtelten Scope ist ein eigenständiges Binding, das das äußere für die Dauer des inneren Scopes überdeckt (shadowing) – das äußere Binding bleibt unverändert, sobald der innere Scope endet. Dasselbe Modell wie in Rust und ML-artigen Sprachen.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S