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

// Definiere eine einfache Funktion
// 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

// Funktion, die einen int zurückgibt
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

// Parameter in geschweiften Klammern {} sind benannte Parameter und standardmäßig optional
// 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

// Die in eckigen Klammern [] sind optionale Positionsparameter
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

SzenarienEmpfohlene VorgehensweiseGrund
Viele Parameter (mehr als 3)Benannte ParameterDie Parameternamen sind an der Aufrufstelle selbstdokumentierend, wodurch es schwierig wird, sie in der falschen Reihenfolge zu übergeben.
Die Bedeutung des Parameters ist unklarBenannte ParameterWerte wie true/false erklären ihren Zweck nicht; ein Name macht sie klarer.
Wenige Parameter und klare BedeutungPositionsparameterWie add(1, 2), prägnant und klar.
Flutter-Widget-KonstruktionBenannte ParameterFlutter-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

// Alle optionalen Parameter haben Standardwerte
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

void main() {
  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

// Funktion höherer Ordnung: akzeptiert eine Funktion als Parameter
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

// Typische Anwendung von Funktionsabschlüssen: Erstellen eines Zählers
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

Der 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.

Weitere Erweiterungen