跳到主要內容

Dart 簡介

本頁面透過 Dart 語言主要功能的示例,對其進行簡要介紹。

要了解有關 Dart 語言的更多資訊,請訪問左側選單中 語言 下列出的深入的各個主題頁面。

要了解 Dart 的核心庫,請檢視核心庫文件。你也可以檢視Dart 速查表,以獲得更具互動性的介紹。

Hello World

#

每個應用都需要頂級的 main() 函式,程式的執行從這裡開始。沒有顯式返回值的函式擁有 void 返回型別。要在控制檯顯示文字,你可以使用頂級的 print() 函式

dart
void main() {
  print('Hello, World!');
}

閱讀更多關於 Dart 中main() 函式的資訊,包括命令列引數的可選引數。

變數

#

即使在型別安全的 Dart 程式碼中,你也可以使用 var 宣告大多數變數,而無需顯式指定它們的型別。由於型別推斷,這些變數的型別由它們的初始值決定

dart
var name = 'Voyager I';
var year = 1977;
var antennaDiameter = 3.7;
var flybyObjects = ['Jupiter', 'Saturn', 'Uranus', 'Neptune'];
var image = {
  'tags': ['saturn'],
  'url': '//path/to/saturn.jpg',
};

閱讀更多關於 Dart 中變數的資訊,包括預設值、finalconst 關鍵字以及靜態型別。

控制流語句

#

Dart 支援常用的控制流語句

dart
if (year >= 2001) {
  print('21st century');
} else if (year >= 1901) {
  print('20th century');
}

for (final object in flybyObjects) {
  print(object);
}

for (int month = 1; month <= 12; month++) {
  print(month);
}

while (year < 2016) {
  year += 1;
}

閱讀更多關於 Dart 中控制流語句的資訊,包括breakcontinueswitchcase 以及assert

函式

#

我們建議指定每個函式的引數和返回值的型別

dart
int fibonacci(int n) {
  if (n == 0 || n == 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

var result = fibonacci(20);

=>箭頭)的簡寫語法對於只包含單個語句的函式非常方便。這種語法在將匿名函式作為引數傳遞時特別有用

dart
flybyObjects.where((name) => name.contains('turn')).forEach(print);

除了展示匿名函式(where() 的引數)之外,此程式碼還展示了你可以將函式用作引數:頂級的 print() 函式是 forEach() 的引數。

閱讀更多關於 Dart 中函式的資訊,包括可選引數、預設引數值和詞法作用域。

註釋

#

Dart 註釋通常以 // 開頭。

dart
// This is a normal, one-line comment.

/// This is a documentation comment, used to document libraries,
/// classes, and their members. Tools like IDEs and dartdoc treat
/// doc comments specially.

/* Comments like these are also supported. */

閱讀更多關於 Dart 中註釋的資訊,包括文件工具如何工作。

匯入

#

要訪問其他庫中定義的 API,請使用 import

dart
// Importing core libraries
import 'dart:math';

// Importing libraries from external packages
import 'package:test/test.dart';

// Importing files
import 'path/to/my_other_file.dart';

閱讀更多關於 Dart 中庫和可見性的資訊,包括庫字首、showhide,以及透過 deferred 關鍵字進行的延遲載入。

#

這是一個包含三個屬性、兩個建構函式和一個方法的類的示例。其中一個屬性不能直接設定,因此它是使用 getter 方法(而不是變數)定義的。該方法使用字串插值來在字串字面量中列印變數的字串等效內容。

dart
class Spacecraft {
  String name;
  DateTime? launchDate;

  // Read-only non-final property
  int? get launchYear => launchDate?.year;

  // Constructor, with syntactic sugar for assignment to members.
  Spacecraft(this.name, this.launchDate) {
    // Initialization code goes here.
  }

  // Named constructor that forwards to the default one.
  Spacecraft.unlaunched(String name) : this(name, null);

  // Method.
  void describe() {
    print('Spacecraft: $name');
    // Type promotion doesn't work on getters.
    var launchDate = this.launchDate;
    if (launchDate != null) {
      int years = DateTime.now().difference(launchDate).inDays ~/ 365;
      print('Launched: $launchYear ($years years ago)');
    } else {
      print('Unlaunched');
    }
  }
}

閱讀更多關於字串的資訊,包括字串插值、字面量、表示式和 toString() 方法。

你可能會像這樣使用 Spacecraft

dart
var voyager = Spacecraft('Voyager I', DateTime(1977, 9, 5));
voyager.describe();

var voyager3 = Spacecraft.unlaunched('Voyager III');
voyager3.describe();

閱讀更多關於 Dart 中類的資訊,包括初始化列表、可選的 newconst、重定向建構函式、factory 建構函式、getter、setter 等等。

列舉

#

列舉是一種列舉預定義的值集或例項的方式,它確保該型別不會有其他例項。

這是一個簡單的 enum 的示例,它定義了一個預定義的行星型別列表

dart
enum PlanetType { terrestrial, gas, ice }

這是一個增強型列舉宣告的示例,它是一個描述行星的類,帶有一組定義的常量例項,即我們太陽系中的行星。

dart
/// Enum that enumerates the different planets in our solar system
/// and some of their properties.
enum Planet {
  mercury(planetType: PlanetType.terrestrial, moons: 0, hasRings: false),
  venus(planetType: PlanetType.terrestrial, moons: 0, hasRings: false),
  // ···
  uranus(planetType: PlanetType.ice, moons: 27, hasRings: true),
  neptune(planetType: PlanetType.ice, moons: 14, hasRings: true);

  /// A constant generating constructor
  const Planet({
    required this.planetType,
    required this.moons,
    required this.hasRings,
  });

  /// All instance variables are final
  final PlanetType planetType;
  final int moons;
  final bool hasRings;

  /// Enhanced enums support getters and other methods
  bool get isGiant =>
      planetType == PlanetType.gas || planetType == PlanetType.ice;
}

你可能會像這樣使用 Planet 列舉

dart
final yourPlanet = Planet.earth;

if (!yourPlanet.isGiant) {
  print('Your planet is not a "giant planet".');
}

閱讀更多關於 Dart 中列舉的資訊,包括增強型列舉要求、自動引入的屬性、訪問列舉值名稱、switch 語句支援等等。

繼承

#

Dart 支援單繼承。

dart
class Orbiter extends Spacecraft {
  double altitude;

  Orbiter(super.name, DateTime super.launchDate, this.altitude);
}

閱讀更多關於擴充套件類、可選的 @override 註解等等。

混入

#

混入是一種在多個類層次結構中重用程式碼的方式。以下是混入宣告

dart
mixin Piloted {
  int astronauts = 1;

  void describeCrew() {
    print('Number of astronauts: $astronauts');
  }
}

要將混入的功能新增到類中,只需用混入擴充套件該類即可。

dart
class PilotedCraft extends Spacecraft with Piloted {
  // ···
}

PilotedCraft 現在擁有 astronauts 欄位和 describeCrew() 方法。

閱讀更多關於混入的資訊。

介面和抽象類

#

所有類都隱式定義一個介面。因此,你可以實現任何類。

dart
class MockSpaceship implements Spacecraft {
  // ···
}

閱讀更多關於隱式介面或顯式interface 關鍵字的資訊。

你可以建立一個抽象類,供具體類擴充套件(或實現)。抽象類可以包含抽象方法(帶有空方法體)。

dart
abstract class Describable {
  void describe();

  void describeWithEmphasis() {
    print('=========');
    describe();
    print('=========');
  }
}

任何擴充套件 Describable 的類都具有 describeWithEmphasis() 方法,該方法呼叫擴充套件者對 describe() 的實現。

閱讀更多關於抽象類和方法的資訊。

非同步

#

透過使用 asyncawait,避免回撥地獄,並使你的程式碼更具可讀性。

dart
const oneSecond = Duration(seconds: 1);
// ···
Future<void> printWithDelay(String message) async {
  await Future.delayed(oneSecond);
  print(message);
}

上面的方法等效於

dart
Future<void> printWithDelay(String message) {
  return Future.delayed(oneSecond).then((_) {
    print(message);
  });
}

如下一個示例所示,asyncawait 有助於使非同步程式碼易於閱讀。

dart
Future<void> createDescriptions(Iterable<String> objects) async {
  for (final object in objects) {
    try {
      var file = File('$object.txt');
      if (await file.exists()) {
        var modified = await file.lastModified();
        print(
          'File for $object already exists. It was modified on $modified.',
        );
        continue;
      }
      await file.create();
      await file.writeAsString('Start describing $object in this file.');
    } on IOException catch (e) {
      print('Cannot create description for $object: $e');
    }
  }
}

你也可以使用 async*,它為你提供了一種良好、可讀的方式來構建流。

dart
Stream<String> report(Spacecraft craft, Iterable<String> objects) async* {
  for (final object in objects) {
    await Future.delayed(oneSecond);
    yield '${craft.name} flies by $object';
  }
}

閱讀更多關於非同步支援的資訊,包括 async 函式、FutureStream 和非同步迴圈(await for)。

異常

#

要丟擲異常,請使用 throw

dart
if (astronauts == 0) {
  throw StateError('No astronauts.');
}

要捕獲異常,請使用帶有 oncatch(或兩者)的 try 語句

dart
Future<void> describeFlybyObjects(List<String> flybyObjects) async {
  try {
    for (final object in flybyObjects) {
      var description = await File('$object.txt').readAsString();
      print(description);
    }
  } on IOException catch (e) {
    print('Could not describe object: $e');
  } finally {
    flybyObjects.clear();
  }
}

請注意,上面的程式碼是非同步的;tryasync 函式中對同步和非同步程式碼都有效。

閱讀更多關於異常的資訊,包括堆疊跟蹤、rethrow 以及 ErrorException 之間的區別。

重要概念

#

隨著你繼續學習 Dart 語言,請記住這些事實和概念

  • 你可以放入變數的任何東西都是一個物件,每個物件都是一個的例項。甚至數字、函式和 null 都是物件。除了 null(如果你啟用健全的空安全)之外,所有物件都繼承自 Object 類。

  • 儘管 Dart 是強型別語言,但型別註解是可選的,因為 Dart 可以推斷型別。在 var number = 101 中,number 被推斷為 int 型別。

  • 如果你啟用空安全,變數不能包含 null,除非你明確允許。你可以透過在其型別末尾加上問號 (?) 來使變數可空。例如,型別為 int? 的變數可能是一個整數,也可能是 null。如果你知道某個表示式永遠不會評估為 null 但 Dart 不認同,你可以新增 ! 來斷言它不是 null(如果它是 null 則丟擲異常)。例如:int x = nullableButNotNullInt!

  • 當你希望明確表示允許任何型別時,請使用 Object? 型別(如果你已啟用空安全)、Object,或者——如果你必須將型別檢查推遲到執行時——使用特殊型別 dynamic

  • Dart 支援泛型型別,例如 List<int>(整數列表)或 List<Object>(任何型別的物件列表)。

  • Dart 支援頂級函式(例如 main()),以及繫結到類或物件的函式(分別為靜態方法和例項方法)。你還可以在函式內部建立函式(巢狀函式或區域性函式)。

  • 類似地,Dart 支援頂級變數,以及繫結到類或物件的變數(靜態變數和例項變數)。例項變數有時也稱為欄位屬性

  • 與 Java 不同,Dart 沒有 publicprotectedprivate 關鍵字。如果識別符號以(_)下劃線開頭,則它是其庫的私有成員。有關詳細資訊,請參閱庫與匯入

  • 識別符號可以以字母或下劃線 (_) 開頭,後跟這些字元和數字的任意組合。

  • Dart 既有表示式(具有執行時值),也有語句(不具有)。例如,條件表示式 condition ? expr1 : expr2 的值為 expr1expr2。將其與沒有值的if-else 語句進行比較。語句通常包含一個或多個表示式,但表示式不能直接包含語句。

  • Dart 工具可以報告兩種問題:警告錯誤。警告只是表明你的程式碼可能無法工作,但它們不會阻止你的程式執行。錯誤可以是編譯時錯誤或執行時錯誤。編譯時錯誤會完全阻止程式碼執行;執行時錯誤會導致程式碼執行時引發異常

附加資源

#

你可以在核心庫文件Dart API 參考中找到更多文件和程式碼示例。本網站的程式碼遵循Dart 風格指南中的約定。