In Dart sind Funktionen ebenfalls Objekte – das unterscheidet sich leicht von anderen Programmiersprachen.
Funktionen sind Objekte erster Klasse
Dart ist eine vollständig objektorientierte Sprache: Funktionen selbst sind Objekte mit dem Typ Function.
Sie können Variablen zugewiesen und als Argumente an andere Funktionen übergeben werden;
Klasseninstanzen lassen sich direkt wie Funktionen aufrufen
1 Standard-Funktionsdefinition
// Vollständige Deklaration mit Rückgabetyp- und Parametertyp-Annotationen
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
Code-Sprache: Dart (dart)
Vollständiges Beispiel
// Zuordnungstabelle der Ordnungszahlen von Edelgasen
final Map<int, String> _nobleGases = {
2: 'He',
10: 'Ne',
18: 'Ar',
36: 'Kr',
54: 'Xe',
86: 'Rn',
};
// Vollständige Deklaration mit Rückgabetyp und Parametertypen
// Der Typ int ist nicht null-fähig; nutze int?, um null-Werte zu akzeptieren
bool isNoble(int? atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
void main() {
print(isNoble(null)); // null ist kein Schlüssel der Map → false
print(isNoble(2)); // Passt zu einem Edelgas → true
print(isNoble(9)); // Kein Treffer → false
print(isNoble(86)); // Passt zu einem Edelgas → true
}
Code-Sprache: Dart (dart)
false
true
false
trueCode-Sprache: JavaScript (javascript)
2 Auslassen von Typannotationen
Der Effective Dart-Styleguide schreibt vollständige explizite Typangaben für öffentliche, nach außen sichtbare APIs vor.
Bei internen privaten Funktionen dürfen Typannotationen weggelassen werden
Beispiel
final Map<int, String> _nobleGases = {
2: 'He',
10: 'Ne',
18: 'Ar',
36: 'Kr',
54: 'Xe',
86: 'Rn',
};
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
void main() {
print(isNoble(null)); // null ist kein Schlüssel der Map → false
print(isNoble(2)); // Passt zu einem Edelgas → true
print(isNoble(9)); // Kein Treffer → false
print(isNoble(86)); // Passt zu einem Edelgas → true
}
Code-Sprache: Dart (dart)
Im obigen Beispiel verzichtet die Funktion isNoble auf den Rückgabetyp bool und den Parametertyp int?, funktioniert aber trotzdem einwandfrei.
Wenn du keine Typangaben schreibst, führt Dart eine automatische Typinferenz durch:
- Parameter
atomicNumber: Kein expliziter Typ → alsdynamicabgeleitet (dynamischer Typ, akzeptiert beliebige Werte: Zahlen, Strings, null) - Rückgabewert: Keine vorangestellte Typannotation → Dart leitet den Rückgabetyp aus dem Ausdruck nach
returnalsboolab, ohne ihn im Code zu schreiben
Warum müssen öffentliche APIs immer explizite Typen haben?
Lesbarkeit: Entwickler, die deine Funktion aufrufen, sehen sofort Ein- und Ausgabetypen, ohne den internen Implementierungscode lesen und raten zu müssen;
Typsicherheit: Der Typ dynamic deaktiviert die statische Typprüfung; falsche Typen führen zu keinen Kompilierfehlern und verursachen oft Laufzeitabstürze;
IDE-Intellisense: Annotierte Typen aktivieren Autovervollständigung und Parameterhinweise im Editor; ohne Typen kann die IDE keine genauen Vorschläge anzeigen.
Wann darf man Typannotationen weglassen?
Nur empfohlen für lokalen privaten Code – Funktionen, die ausschließlich innerhalb der aktuellen Datei verwendet und nie von außen aufgerufen werden.
Pfeil-Kurzschreibweise (=>)
Wenn der Funktionskörper (Code innerhalb von {}) nur einen einzigen Rückgabeausdruck enthält, kannst du die Pfeilsyntax verwenden.
Beispiel
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
Code-Sprache: Dart (dart)
=> exprentspricht{ return expr; };- Zwischen Pfeil und Semikolon dürfen nur Ausdrücke stehen; Anweisungen wie
ifsind verboten (nutze stattdessen ternäre Operatoren).
// Zuordnungstabelle der Ordnungszahlen von Edelgasen
final Map<int, String> _nobleGases = {
2: 'Helium',
10: 'Neon',
18: 'Argon',
36: 'Krypton',
54: 'Xenon',
86: 'Radon',
};
// Pfeil-Kurzfunktion: Einzeiliger Ausdruck gibt direkt zurück, äquivalent zu Blockfunktionen mit return
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
void main() {
// Vorhandene Edelgase testen
print(isNoble(2)); // true
print(isNoble(18)); // true
// Normale Elemente testen
print(isNoble(6)); // false (Kohlenstoff)
print(isNoble(99)); // false (kein passendes Element)
}
Code-Sprache: Dart (dart)

Parameter
Funktionen unterstützen erforderliche Positionsargumente, gefolgt von genau einer der zwei Optionen: benannte Parameter oder optionale Positionsargumente – sie lassen sich nicht mischen.
Bei der Definition oder dem Aufruf von Parametern sind nachgestellte Kommas , erlaubt, um die Code-Lesbarkeit zu verbessern.
1. Benannte Parameter Named parameters
Eingekapselt in {}, standardmäßig optional; füge required hinzu, um eine zwingende Übergabe zu erzwingen.
1) Einfache null-fähige benannte Parameter (kein Standardwert, Standardwert ist null, der Typ muss mit ? als null-fähig markiert werden)
void enableFlags({bool? bold, bool? hidden}) {}
// Bei Aufruf explizit Parameternamen angeben
enableFlags(bold: true, hidden: false);
Code-Sprache: Dart (dart)
Vollständiges Beispiel
/// Textstil-Flags aktivieren: fett, ausgeblendet
void enableFlags({bool? bold, bool? hidden}) {
print('Fett: $bold, Ausgeblendet: $hidden');
}
void main() {
// Alle benannten Parameter übergeben
enableFlags(bold: true, hidden: false);
// Nur einen benannten Parameter übergeben, der andere wird null
enableFlags(bold: true);
// Nur hidden übergeben
enableFlags(hidden: true);
// Keine Parameter übergeben, beide Werte sind null
enableFlags();
}
Code-Sprache: Dart (dart)
Ausgabeergebnis
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Fett: true, Ausgeblendet: false
Fett: true, Ausgeblendet: null
Fett: null, Ausgeblendet: true
Fett: null, Ausgeblendet: nullCode-Sprache: JavaScript (javascript)
2) Festlegen von Kompilierzeit-Konstanten als Standardwerte (keine Nullmarkierung nötig, da ein Standardwert existiert)
void enableFlags({bool bold = false, bool hidden = false}) {}
enableFlags(bold: true); // hidden nutzt automatisch false
Code-Sprache: Dart (dart)
Beispiel
/// Textstil-Flags aktivieren: fett, ausgeblendet
void enableFlags({bool bold = false, bool hidden = false}) {
print('Fett: $bold, Ausgeblendet: $hidden');
}
void main() {
enableFlags();//Keine Parameter übergeben, beide nutzen Standardwert false → Fett: false, Ausgeblendet: false
}
Code-Sprache: Dart (dart)
3) Zwingende benannte Parameter mit required (Hinweis: Sehr häufig in Konstruktoren von Flutter-Widgets verwendet. Das folgende Beispiel ist Flutter-Code; mehr erfährst du in Flutter-Tutorials.)
const Scrollbar({super.key, required Widget child});
// required-Parameter akzeptieren ebenfalls null-fähige Typen
const Scrollbar({super.key, required Widget? child});
Code-Sprache: Dart (dart)
Dart schreibt nicht vor, dass benannte Parameter am Ende der Parameterliste stehen müssen; sie können beliebig eingefügt werden
repeat(times: 2, () {})Code-Sprache: CSS (css)
2. Optionale Positionsargumente Optional positional parameters
Eingekapselt in [], Standardwert ist null bei Weglassen; konstante Standardwerte können definiert werden.
// Kein Standardwert, Typ mit ? markiert
String say(String from, String msg, [String? device]) {
var result = '$from says $msg';
if (device != null) result = '$result with a $device';
return result;
}
assert(say('Bob', 'Howdy') == 'Bob says Howdy');
assert(say('Bob', 'Howdy', 'smoke signal') == 'Bob says Howdy with a smoke signal');
Code-Sprache: Dart (dart)
Vollständiges Beispiel
// [String? device] optionales Positionsargument ohne Standardwert, null bei Weglassen
String say(String from, String msg, [String? device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device'; //Geräteinformation an den Satz anhängen, falls device nicht null ist
}
return result;
}
void main() {
// Drittes optionales Argument weglassen
String res1 = say('Bob', 'Howdy');
print(res1);
// Drittes optionales Positionsargument übergeben
String res2 = say('Bob', 'Howdy', 'smoke signal');
print(res2);
// Manuell null an das optionale Argument übergeben
String res3 = say('Alice', 'Hi', null);
print(res3);
}
Code-Sprache: Dart (dart)
Standardwerte festlegen:
String say(String from, String msg, [String device = 'carrier pigeon']) {
return '$from says $msg with a $device';
}
assert(say('Bob', 'Howdy') == 'Bob says Howdy with a carrier pigeon');
Code-Sprache: Dart (dart)
Vollständiges Beispiel
// Optionales Positionsargument mit Standardwert carrier pigeon (Brieftaube)
String say(String from, String msg, [String device = 'carrier pigeon']) {
return '$from says $msg with a $device';
}
void main() {
// Drittes optionales Argument weglassen, automatisch Standardwert carrier pigeon nutzen
String res1 = say('Bob', 'Howdy');
print(res1); //Bob says Howdy with a carrier pigeon
// Eigenes Gerät übergeben, um Standardwert zu überschreiben
String res2 = say('Bob', 'Howdy', 'smoke signal');
print(res2); //Bob says Howdy with a smoke signal
String res3 = say('Alice', 'Hello', 'mobile phone');
print(res3); // Alice says Hello with a mobile phone
String res4 = say('Jack', 'Tom', 'website foxdevelop.com');
print(res4); // Jack says Tom with a website foxdevelop.com
}
Code-Sprache: Dart (dart)
Ausgabeergebnis
Built firstdart:firstdart.
Bob says Howdy with a carrier pigeon
Bob says Howdy with a smoke signal
Alice says Hello with a mobile phone
Jack says Tom with a website foxdevelop.comCode-Sprache: JavaScript (javascript)
main () Einstiegsfunktion
Jedes Dart-Programm benötigt eine Top-Level-Funktion main() – sie ist der einzige Ausführungseinstiegspunkt des Programms.
- Basisversion ohne Parameter
void main() {
print('Hello, welcome to foxdevelop.com!');
}
Code-Sprache: Dart (dart)
Hello, welcome to foxdevelop.com!Code-Sprache: CSS (css)
- Kommandozeilenprogramm mit Startargumenten
// Ausführungsbefehl: dart run firstdart.dart 1 test
void main(List<String> arguments) {
print(arguments); // [1, test]
}
Code-Sprache: Dart (dart)
Nutze die offizielle Bibliothek args für komplexe Parsing-Aufgaben von Kommandozeilenargumenten.
Ersetze firstdart.dart oben durch deinen eigenen Dart-Dateinamen

Funktionen als Objekte erster Klasse First-class objects
1. Funktionen als Parameter übergeben
void printElement(int element) => print(element);
var list = [1, 2, 3];
list.forEach(printElement); // Funktion direkt übergeben
Code-Sprache: Dart (dart)
Vollständiges Beispiel
void main() {
void printElement(int element) => print(element);
var list = [1, 2, 3];
list.forEach(printElement); // Funktion direkt übergeben
}
Code-Sprache: Dart (dart)
Ausgabe
1
2
3
2. Anonyme Funktionen einer Variable zuweisen
void main() {
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
print(loudify('hello')); //!!! HELLO !!!
}
Code-Sprache: Dart (dart)
Funktionstyp Function Type
Du kannst Typen für Funktionsvariablen explizit deklarieren
Format: Rückgabetyp Function(ParameterListe, {BenannteParameter})
void greet(String name, {String greeting = 'Hello'}) => print('$greeting $name!');
// Funktionsvariable deklarieren
void Function(String, {String greeting}) g = greet;
g('Dash', greeting: 'Howdy');
Code-Sprache: Dart (dart)
Mit typedef erstellst du Aliase für Funktionstypen, um Wiederverwendbarkeit und Lesbarkeit zu verbessern.
{String greeting}) → Ein benannter Parameter greeting vom Typ String
void main() {
void greet(String name, {String greeting = 'Hello'}) => print('$greeting $name!');
// Funktionsvariable deklarieren
void Function(String, {String greeting}) g = greet;
g('Jack', greeting: 'Howdy');
}
Code-Sprache: Dart (dart)
Ausgabe
Howdy Jack!
Anonyme Funktionen (Lambda / Closure Abschluss)
Funktionen ohne eigenen Namen, zwei Schreibweisen:
- Block-Syntax (mehrzeilig)
void main() {
const list = ['apples', 'bananas'];
var uppercaseList = list.map((item) {
return item.toUpperCase();
}).toList();
print(uppercaseList);
}
Code-Sprache: Dart (dart)
(item) { return item.toUpperCase(); } im obigen Code ist eine anonyme Funktion (Lambda)
Ausgabe: [APPLES, BANANAS]
- Pfeil-Kurzschreibweise (einzeiliger Ausdruck)
void main() {
const list = ['fox', 'develop','foxdevelop.com'];
var uppercaseList = list.map((item) => item.toUpperCase()).toList();
uppercaseList.forEach((item) => print('$item: ${item.length}'));
}
Code-Sprache: Dart (dart)
Ausgabe
FOX: 3
DEVELOP: 7
FOXDEVELOP.COM: 14Code-Sprache: HTTP (http)
Lexikalischer Gültigkeitsbereich Lexical scope
Dart nutzt statische lexikalische Gültigkeitsbereiche: Der Gültigkeitsbereich einer Variable ergibt sich aus der Klammerhierarchie des Codes, innere Bereiche können alle Variablen äußerer Bereiche zugreifen.
bool topLevel = true;
void main() {
var insideMain = true;
void myFunction() {
var insideFunction = true;
void nestedFunction() {
var insideNestedFunction = true;
// Alle zugänglich
assert(topLevel && insideMain && insideFunction && insideNestedFunction);
}
}
}
Code-Sprache: Dart (dart)
Lexikalische Abschlüsse Lexical closures
Abschluss: Ein Funktionsobjekt kann Variablen aus dem äußeren Gültigkeitsbereich erfassen und speichern – auch nach Verlassen des ursprünglichen Bereichs bleibt der Zugriff möglich.
Function makeAdder(int addBy) {
// Äußere Variable addBy erfassen
return (int i) => addBy + i;
}
void main() {
var add2 = makeAdder(2);
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
Code-Sprache: Dart (dart)
Schritt-für-Schritt-Analyse des obigen Ablaufs
Schritt 1: var add2 = makeAdder(2);
makeAdderausführen,addBy = 2übergeben- Anonyme Funktion erstellen:
(int i) => 2 + i - Diese Funktion der Variable
add2zuweisen. Ab dann ist add2 ein Funktionsobjekt mit dem Körper(int i) => 2 + i; es nimmt einen int-Wert i entgegen und gibt i+2 zurück - Die Ausführung von
makeAdderendet, aber die anonyme Funktion merkt sich dauerhaftaddBy=2
Schritt 2: var add4 = makeAdder(4);
makeAddererneut ausführen,addBy = 4übergeben- Eine völlig separate neue anonyme Funktion erstellen:
(int i) => 4 + i - An
add4zuweisen, das eine eigene unabhängige Kopie vonaddBy=4speichert und sich nicht mit add2 beeinflusst. Der Wert addBy liegt separat in den zwei Funktionsobjekten add2 und add4 gespeichert, einer hält 2, der andere 4
- Der Aufruf von
makeAdder(2)erzeugt einen unabhängigen Abschluss mit einem einzeln gebundenen WertaddBy = 2, zugewiesen anadd2; - Der Aufruf von
makeAdder(4)erzeugt einen brandneuen separaten Abschluss mit einem einzeln gebundenen WertaddBy = 4, zugewiesen anadd4; add2undadd4sind vollständig getrennte Funktionsobjekte, jedes speichert privat seine erfassteaddBy-Variable ohne gegenseitige Beeinträchtigung.
Schritt 3: add2(3) aufrufen
Interne Funktion ausführen: 2 + 3 = 5, Assertion erfüllt
Schritt 4: add4(3) aufrufen
Interne Funktion ausführen: 4 + 3 = 7, Assertion erfüllt
Funktions-Tear-offs
Wenn du eine Funktion / Methode ohne Klammern aufrufst, erzeugst du einen Tear-off (leichter Abschluss), der handgeschriebene anonyme Lambdas ersetzt und den Code kompakter macht.
Dies ist die empfohlene Schreibweise; übergebe einfach die Funktion direkt.
var charCodes = [68, 97, 114, 116];
var buffer = StringBuffer();
charCodes.forEach(print); // Funktions-Tear-off
charCodes.forEach(buffer.write); // Methoden-Tear-off
Code-Sprache: Dart (dart)
Langwierige äquivalente Schreibweise
charCodes.forEach((code) => print(code));
charCodes.forEach((code) => buffer.write(code));
Code-Sprache: Dart (dart)
Prüfung der Funktionsgleichheit
- Top-Level-Funktionen, statische Methoden:
==gibt true zurück, wenn die Funktionsnamen exakt übereinstimmen; - Instanzmethoden: Nur Tear-offs, die an die selbe Objektinstanz gebunden sind, werden als gleich gewertet.
void foo() {}
class A {
static void bar() {}
void baz() {}
}
void main() {
var x = foo;
assert(foo == x);
x = A.bar;
assert(A.bar == x);
var v = A(), w = A(), y = w;
x = w.baz;
assert(y.baz == x); // Gleiche Instanz → gleich
assert(v.baz != w.baz); // Verschiedene Instanzen → ungleich
}
Code-Sprache: Dart (dart)
Rückgabewerte Return values
- Jede Funktion hat einen Rückgabewert: Fehlt explizites
return, wird am Ende implizitreturn null;angehängt
foo() {}
assert(foo() == null);
Code-Sprache: Dart (dart)
- Mehrere Werte zurückgeben: Record-Tupel verwenden
(String, int) foo() {
return ('something', 42);
}
Code-Sprache: Dart (dart)
Getter & Setter Zugriffsmethoden
Jedes Lesen oder Zuweisen einer Eigenschaft ruft im Grunde einen Getter oder Setter auf. Normale Variablen erzeugen automatisch implizite Zugriffsmethoden; du kannst sie auch manuell explizit definieren.
Vorteil: Externer Code greift einheitlich mit .Eigenschaftsname zu, interne Logik kann jederzeit geändert werden, ohne den aufrufenden externen Code anzupassen.
String _secret = 'Hello';
// Getter für Lesezugriff
String get secret {
print('Getter aufgerufen');
return _secret.toUpperCase();
}
// Setter für Zuweisungen
set secret(String newMsg) {
print('Setter aufgerufen');
if (newMsg.isNotEmpty) _secret = newMsg;
}
void main() {
print(secret); // Lesen, löst Getter aus → HELLO
secret = 'Dart is fun'; // Zuweisung, löst Setter aus
print(secret); // DART IS FUN
}
Code-Sprache: Dart (dart)
* Generatoren Generators
Erzeugen Sequenzen bedarfsgesteuert verzögert, zwei Varianten: synchron und asynchron, nutze yield zur Ausgabe von Werten.
- Synchroner Generator
sync*, gibtIterablezurück
Iterable<int> naturalsTo(int n) sync* {
int k = 0;
while (k < n) yield k++;
}
Code-Sprache: Dart (dart)
- Asynchroner Generator
async*, gibtStreamzurück
Stream<int> asyncNaturalsTo(int n) async* {
int k = 0;
while (k < n) yield k++;
}
Code-Sprache: Dart (dart)
- Rekursiver Generator-Optimierung
yield*(Delegiert an einen anderen Generator zur Leistungsverbesserung)
Iterable<int> naturalsDownFrom(int n) sync* {
if (n > 0) {
yield n;
yield* naturalsDownFrom(n - 1);
}
}
Code-Sprache: Dart (dart)
Function