Aufbau einer Funktion
Die allgemeine Form einer Zero-Funktion:
fun name(param1: Typ1, param2: Typ2) -> Rückgabetyp {
// body
return wert
}
Bestandteile:
fun– das Schlüsselwort, das eine Funktion einleitet.name– der Name der Funktion.(param1: Typ1, ...)– Parameterliste. Jeder Parameter hat einen expliziten Typ.-> Rückgabetyp– der Rückgabetyp.{ ... }– der Body, ein Block aus Statements.return wert– verlässt die Funktion mitwert.
Ein kleines konkretes Beispiel:
fun double(value: i32) -> i32 {
return value * 2
}
Das ist die ganze Funktion. Sie nimmt einen i32, gibt einen anderen zurück und macht keine I/O. Innerhalb des Bodys ist value ein let-artiges Binding – du kannst es wie jede andere lokale Variable verwenden.
Funktionen aufrufen
Aufrufe sehen genau so aus, wie du es erwartest:
let result = double(21)
Das Argument muss zum Parameter-Typ passen. Das Ergebnis wird an result gebunden, dessen Typ der Compiler als i32 inferiert, weil double ein i32 zurückgibt.
Ein durchgespieltes Beispiel, das einen Helfer und main zusammenführt – klick Run, um es in Aktion zu sehen:
Du solltest math works\n auf stdout bekommen.
pub und Sichtbarkeit
Standardmäßig ist eine Funktion, die in einer Datei deklariert wird, privat für diese Datei (oder dieses Modul – die Sichtbarkeitsregeln werden strenger, wenn Projekte wachsen). Um eine Funktion außerhalb ihres Moduls bereitzustellen, stell pub davor:
pub fun greet() -> String {
return "hello\n"
}
Ohne pub kann Code in anderen Modulen greet nicht aufrufen. Die Runtime muss main von außerhalb jedes benutzerdefinierten Moduls aufrufen, weshalb main immer pub ist.
Die „standardmäßig privat"-Regel ist eine gute, an die man sich halten sollte. Markiere nur das, was Schnittstelle sein soll; der Rest bleibt innerhalb des Moduls.
Rückgabetypen
Jede Funktion deklariert ihren Rückgabetyp nach ->. Gängige Rückgabetypen:
fun answer() -> i32 { return 42 }
fun ok() -> bool { return true }
fun label() -> String { return "ready\n" }
fun nothing() -> Void { }
Void ist der Rückgabetyp einer Funktion, die ihre Arbeit über Seiteneffekte erledigt, statt einen Wert zu liefern. Eine Void-Funktion braucht kein explizites return – aus dem Ende des Bodys herauszufallen reicht.
fun log(world: World, message: String) -> Void raises {
check world.out.write(message)
}
Funktionsaufrufe, die einen Wert verwerfen
Wenn eine Funktion einen Wert zurückgibt und dich der nicht interessiert, musst du den Rückgabewert trotzdem bestätigen. Idiomatisch bindet man ihn mit let:
ignored ist ein Binding, das der Rest der Funktion nie liest. Die Konvention, den Namen ignored (oder _) zu verwenden, signalisiert, dass das Verwerfen Absicht ist. Das ist mehr Reibung als ein stilles Verwerfen, und das ist Absicht: In einer Sprache, in der Agenten Code lesen und generieren, ist ein ungelesener Wert oft ein Bug, den man sichtbar machen will.
Die Rolle von raises
Eine Funktion, die fehlschlagen könnte, deklariert das in der Signatur. Wir haben das bei main gesehen:
pub fun main(world: World) -> Void raises {
check world.out.write("hello\n")
}
Die raises-Klausel kann bloß sein (jeder Fehler) oder spezifisch:
fun validate(ok: Bool) -> i32 raises { InvalidInput } {
if ok == false {
raise InvalidInput
}
return 42
}
raises { InvalidInput } heißt: „diese Funktion kann mit InvalidInput fehlschlagen, und mit nichts anderem." Aufrufer müssen check (oder eine ausführlichere Handling-Form) verwenden, um den Fehler weiterzureichen oder zu behandeln.
Raises und Check geht in die Tiefe, einschließlich was bei mehreren Fehlertypen passiert und wie check mit der raises-Klausel des Aufrufers interagiert.
Generische Funktionen
Wenn eine Funktion über mehr als einen Typ arbeiten soll, deklarier Typparameter in spitzen Klammern:
fun makePair<T, U>(left: T, right: U) -> Pair<T, U> {
return Pair { left: left, right: right }
}
T und U sind Typparameter – der Aufrufer entscheidet, was sie sind. Der Aufruf makePair(40, 2_u8) ergibt ein Pair<i32, u8>. Siehe Generics für die ganze Geschichte, einschließlich generischer Shapes und Constraints.
Wo Funktionen leben
In einem kleinen Programm schreibst du Funktionen direkt in deine .0-Datei. In einem Paket verteilst du Funktionen über Dateien unter src/, und der Compiler löst dateiübergreifende Referenzen für dich auf. Die Grundlagen bleiben gleich – fun, Parameter, Rückgabetyp, Body – egal, wo die Funktion physisch liegt.
Stil-Hinweise
Ein paar Konventionen, die du in den offiziellen Beispielen sehen wirst:
- Kleingeschriebene Funktionsnamen, Wörter zusammen (
makePair) oder per camelCase getrennt. Die Standardbibliothek tendiert zu camelCase. - Ein Rückgabewert pro Funktion. Brauchst du mehrere Werte, bau dir eine kleine
shape– das ist klarer als ein Tupel-aus-Pair-aus-Tupel zurückzugeben. Void-Funktionen machen nurcheck-Aufrufe; Funktionen, die einen Wert berechnen, vermeiden I/O, wo es geht. Die Trennung ist teils Kultur, teils erzwungen – eine reine Rechen-Funktion bekommt keinworldund kann darum buchstäblich keine I/O machen.
Der letzte Punkt verdient ein paar Sätze mehr. Weil I/O hinter der World-Capability lebt und World explizit übergeben wird, sagt dir die Signatur einer Funktion, ob sie I/O macht. Funktionen, deren Signaturen World nicht erwähnen, sind hinsichtlich der Außenwelt rein. Auf diese Eigenschaft können sich Agenten (und Menschen) verlassen, ohne den Body zu lesen.
Als Nächstes: If/Else
Du hast if schon vorbeihuschen sehen – das nächste Dokument behandelt If/Else-Ausdrücke im Detail, einschließlich wie sie mit Bindings interagieren und was bewusst fehlt (keine implizite Wahrheits-Interpretation, kein Ternär-Operator).
Häufig gestellte Fragen
Wie deklariere ich eine Funktion in Zero?
Mit fun: fun name(param: Typ) -> Rückgabetyp { body }. Stell pub davor, um die Funktion außerhalb ihres Moduls sichtbar zu machen. Hänge raises nach dem Rückgabetyp an, wenn die Funktion fehlschlagen kann. Beispiel: pub fun double(value: i32) -> i32 { return value * 2 }.
Was macht das pub-Schlüsselwort?
pub-Schlüsselwort?pub markiert eine Deklaration als öffentlich – sichtbar für Code außerhalb des aktuellen Moduls. Ohne pub ist eine Funktion privat für die Datei (oder das Paket), in der sie deklariert wurde. Der konventionelle Einstiegspunkt pub fun main muss öffentlich sein, damit die Runtime ihn finden und aufrufen kann.
Wie gebe ich in Zero einen Wert aus einer Funktion zurück?
Schreibe return wert im Funktions-Body. Der Ausdruck muss zum deklarierten Rückgabetyp passen. Eine Funktion mit Rückgabetyp Void liefert nichts zurück und braucht kein explizites return – einfach hinten herausfallen reicht.
Können Zero-Funktionen mehrere Parameter haben?
Ja. Liste sie in Klammern durch Kommas getrennt mit Name und Typ auf: fun add(a: i32, b: i32) -> i32 { return a + b }. Jeder Parameter ist im Funktions-Body ein let-artiges Binding. Zero verlangt explizite Typen an Parametern – bei Funktionsdeklarationen gibt es keine Parameter-Typinferenz.
Was bedeutet raises in einer Funktionssignatur?
raises in einer Funktionssignatur?raises deklariert, dass die Funktion fehlschlagen kann. Ein bloßes raises erlaubt jeden Fehlertyp; raises { InvalidInput } schränkt es auf einen bestimmten benannten Fehler ein. Aufrufer müssen check (oder ein anderes Fehler-Konstrukt) verwenden, um die Möglichkeit des Fehlschlags zu bestätigen – sie können sie nicht stillschweigend ignorieren.