Dart-Funktionen
Eine Funktion ist die grundlegende Einheit zur Organisation von Code; sie kapselt eine wiederverwendbare Logik, die bei Bedarf aufgerufen werden kann.
Das Funktionssystem von Dart ist sehr flexibel und unterstützt Funktionen wie benannte Parameter, optionale Parameter, Pfeilfunktionen und Funktionen höherer Ordnung.
Funktionsdefinition und Rückgabewert
Eine Funktion besteht aus einem Rückgabetyp, einem Funktionsnamen, einer Parameterliste und einem Funktionskörper.
Beispiel
// String ist der Rückgabetyp, greet ist der Funktionsname, (String name) ist die Parameterliste
String greet(String name) {
return 'Hello, $name! Welcome to EXAMPLE.';
}
// Funktionen ohne Rückgabewert verwenden void
void printWelcome() {
print('=== BEISPIEL Dart-Tutorial ===');
}
void main() {
printWelcome();
// Funktion aufrufen und Rückgabewert empfangen
String message = greet('Xiao Ming');
print(message);
}
=== EXAMPLE Dart 教程 === 你好,小明!欢迎来到 EXAMPLE.
Rückgabewert
Jede Funktion hat einen Rückgabewert.
Wenn es keine explizite Rückgabe gibt, gibt die Funktion implizit null zurück (aber unter Null-Sicherheit würde dies zu einem Typkonflikt führen, daher wird üblicherweise void verwendet, um anzuzeigen, dass es keinen Rückgabewert gibt).
Beispiel
int add(int a, int b) {
return a + b;
}
// Pfeilsyntax als Kurzform für Funktionen mit einem einzigen Ausdruck verwenden
int multiply(int a, int b) => a * b;
// void gibt an, dass es keinen aussagekräftigen Rückgabewert gibt
void log(String msg) {
print('[BEISPIEL Log] $msg');
}
void main() {
print('3 + 5 = ${add(3, 5)}');
print('3 × 5 = ${multiply(3, 5)}');
log('Funktionslernen abgeschlossen');
}
3 + 5 = 8 3 × 5 = 15 [EXAMPLE 日志] 函数学习完成
Benannte Parameter und optionale Parameter
Dart-Parameter werden in zwei Typen unterteilt: erforderliche Parameter und optionale Parameter.
Optionale Parameter werden weiter in benannte Parameter und Positionsparameter unterteilt.
Benannte Parameter
Benannte Parameter werden in geschweifte Klammern {} eingeschlossen und beim Aufruf über den Parameternamen übergeben, sodass die Reihenfolge beliebig sein kann.
Beispiel
// Das Schlüsselwort required kennzeichnet sie als erforderlich
String createUser({
required String name, // Erforderlicher benannter Parameter
int age = 0, // Optional, Standardwert ist 0
String? email, // Optional, kann null sein
bool isVip = false, // Optional, Standardwert ist false
}) {
var info = 'Benutzername: $name, Alter: $age';
if (email != null) {
info += ', E-Mail: $email';
}
if (isVip) {
info += ' [VIP-Benutzer]';
}
return info;
}
void main() {
// Benannte Parameter: werden über den Parameternamen übergeben, die Reihenfolge spielt keine Rolle
print(createUser(name: 'example', age: 10));
print(createUser(name: 'admin', email: '[email protected]', isVip: true));
// Erforderliche Parameter können nicht weggelassen werden
// createUser(); // Fehler: erforderlicher Parameter name fehlt
}
用户名: example, 年龄: 10 用户名: admin, 邮箱: [email protected] [VIP用户]
Positionsparameter
Positionsparameter werden in eckige Klammern [] eingeschlossen, und beim Aufruf werden sie in der Reihenfolge übergeben.
Beispiel
String buildUrl(String host, [String path = '/', int port = 80]) {
return 'http://$host:$port$path';
}
void main() {
// Nur erforderliche Parameter übergeben, optionale Parameter verwenden Standardwerte
print(buildUrl('www.example.com'));
// 2 Parameter übergeben
print(buildUrl('www.example.com', '/dart'));
// 3 Parameter übergeben
print(buildUrl('localhost', '/api', 8080));
}
http://www.example.com:80/ http://www.example.com:80/dart http://localhost:8080/api
Benannte Parameter vs. Positionsparameter: Wie man wählt
| Szenarien | Empfohlene Vorgehensweise | Grund |
|---|---|---|
| Viele Parameter (mehr als 3) | Benannte Parameter | Die Parameternamen sind an der Aufrufstelle selbstdokumentierend, wodurch es schwierig wird, sie in der falschen Reihenfolge zu übergeben. |
| Die Bedeutung des Parameters ist unklar | Benannte Parameter | Werte wie true/false erklären ihren Zweck nicht; ein Name macht sie klarer. |
| Wenige Parameter und klare Bedeutung | Positionsparameter | Wie add(1, 2), prägnant und klar. |
| Flutter-Widget-Konstruktion | Benannte Parameter | Flutter-Standardstil |
Eine Funktion kann sowohl optionale Positionsparameter als auch optionale benannte Parameter verwenden. Man kann nur eines wählen.
Standardwerte für Parameter
Optionalen Parametern können Standardwerte zugewiesen werden, die verwendet werden, wenn der Aufrufer diesen Parameter nicht übergibt.
Beispiel
String formatMessage(
String content, {
String prefix = '[EXAMPLE]',
String suffix = '',
bool uppercase = false,
}) {
var result = 'prefix $content $suffix';
return uppercase ? result.toUpperCase() : result;
}
void main() {
// Alle Standardwerte verwenden
print(formatMessage('Dart tutorial updated'));
// Einige Standardwerte überschreiben
print(formatMessage('Important notice', prefix: '[Announcement]', suffix: '!!!'));
// Standardwerte überschreiben + Großschreibung aktivieren
print(formatMessage('error', prefix: [Error], uppercase: wahr));
}
[EXAMPLE] Dart 教程更新了 [公告] 重要通知 !!! [错误] ERROR
Standardwerte müssen Kompilierzeitkonstanten sein. Das heißt, der Standardwert kann nicht DateTime.now() oder der Rückgabewert einer Funktion sein (es sei denn, die Funktion ist const). Wenn Sie den Standardwert zur Laufzeit bestimmen müssen, können Sie ihn mit ?? innerhalb des Funktionskörpers behandeln.
Pfeilfunktionen und anonyme Funktionen
Wenn der Funktionskörper nur einen einzigen Ausdruck enthält, kann die Pfeilsyntax (=>) als Kurzschreibweise verwendet werden.
Eine anonyme Funktion ist eine Funktion ohne Namen, die normalerweise als Argument an eine andere Funktion übergeben wird.
Beispiel
var numbers = [1, 2, 3, 4, 5];
// Anonyme Funktion (vollständige Syntax)
numbers.forEach((number) {
print(BEISPIEL Nummer: $number);
});
print('---');
// Pfeilfunktion (Kurzschreibweise für Einzelausdruck)
var doubled = numbers.map((n) => n * 2);
print(Verdoppelt: $doubled);
// Verwendung von Pfeilfunktionen in Funktionsdefinitionen
// Wenn der Funktionskörper nur eine return-Anweisung hat, kann => als Kurzschreibweise verwendet werden
int square(int x) => x * x;
print(5 zum Quadrat: ${square(5)});
// Eine anonyme Funktion in einer Variablen speichern
var sayHello = (String name) => Hallo, $name!;
print(sayHello('Beispiel'));
}
EXAMPLE 数字: 1 EXAMPLE 数字: 2 EXAMPLE 数字: 3 EXAMPLE 数字: 4 EXAMPLE 数字: 5 --- 翻倍: (2, 4, 6, 8, 10) 5 的平方: 25 你好,example!
Funktionen höherer Ordnung und Closures
Eine Funktion höherer Ordnung ist eine Funktion, die eine Funktion als Argument empfangen oder eine Funktion als Ergebnis zurückgeben kann.
Eine Closure ist eine Funktion, die auf Variablen in ihrem lexikalischen Gültigkeitsbereich zugreifen kann, selbst wenn die Funktion außerhalb dieses Bereichs aufgerufen wird.
Funktionen höherer Ordnung
Beispiel
List<int> filterList(
List<int> items, bool Function(int) predicate) {
return items.where(predicate).toList();
}
// Funktion höherer Ordnung: gibt eine Funktion zurück
Function makeMultiplier(int factor) {
// Gibt eine Closure zurück: merkt sich den äußeren Faktor
return (int n) => n * factor;
}
void main() {
var numbers = [10, 15, 20, 25, 30];
// Eine anonyme Funktion als Filterbedingung übergeben
var bigNumbers = filterList(numbers, (n) => n > 18);
print(BEISPIEL Zahlen größer als 18: $bigNumbers);
// Die zurückgegebene Funktion abrufen
var doubleIt = makeMultiplier(2);
var tripleIt = makeMultiplier(3);
print('5 × 2 = ${doubleIt(5)}');
print('5 × 3 = ${tripleIt(5)}');
}
EXAMPLE 大于18的数: [20, 25, 30] 5 × 2 = 10 5 × 3 = 15
Funktionsabschluss
Ein Funktionsabschluss ist ein Funktionsobjekt, das auf Variablen in seinem lexikalischen Gültigkeitsbereich zugreifen kann, selbst wenn die Funktion außerhalb des ursprünglichen Gültigkeitsbereichs aufgerufen wird.
Beispiel
Function makeCounter() {
int count = 0; // Diese Variable wird von der zurückgegebenen Funktion „eingefangen“
return () {
count++;
return count;
};
}
void main() {
// counterA und counterB haben jeweils ihren eigenen unabhängigen count
var counterA = makeCounter();
var counterB = makeCounter();
print(BEISPIEL Zähler A: ${counterA()}); // 1
print(BEISPIEL Zähler A: ${counterA()}); // 2
print(BEISPIEL Zähler B: ${counterB()}); // 1 (unabhängiger count)
print(BEISPIEL Zähler A: ${counterA()}); // 3
}
EXAMPLE 计数器 A: 1 EXAMPLE 计数器 A: 2 EXAMPLE 计数器 B: 1 EXAMPLE 计数器 A: 3
Weitere ErweiterungenDer Schlüssel zu Closures ist, dass die innere Funktion sich an die Variablen der äußeren Funktion „erinnert“, selbst nachdem die äußere Funktion ihre Ausführung beendet hat. Jeder Aufruf von makeCounter() erzeugt eine brandneue count-Variable und Closure, sodass sich mehrere Zähler nicht gegenseitig beeinflussen.