內容

此頁面透過其主要功能的範例,提供 Dart 語言的簡要介紹。

若要深入了解 Dart 語言,請參閱左側選單中 **語言** 下列出的深入個別主題頁面。

若要涵蓋 Dart 的核心函式庫,請查看 核心函式庫文件。您也可以嘗試 Dart 參考手冊 codelab,以獲得更實作的介紹。

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,以及更多內容。

列舉

#

列舉是一種列舉預定義值或實例的集合,並確保不會有其他該類型的實例。

以下是定義預定義行星類型簡單清單的簡單列舉範例

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註解,以及更多內容。

混合

#

Mixins 是在多個類別階層中重複使用程式碼的一種方式。以下是 mixin 宣告

dart
mixin Piloted {
  int astronauts = 1;

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

若要將 mixin 的功能新增到類別,只需使用 mixin 延伸類別即可。

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

PilotedCraft 現在具有astronauts欄位,以及describeCrew()方法。

閱讀更多有關 mixins 的資訊。

介面和抽象類別

#

所有類別都隱含定義一個介面。因此,您可以實作任何類別。

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

閱讀更多有關隱含介面,或有關明確的介面關鍵字

您可以建立一個抽象類別,讓具體類別延伸 (或實作)。抽象類別可以包含抽象方法 (主體為空)。

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();
  }
}

請注意,上述程式碼是非同步的;try同時適用於同步程式碼和async函式中的程式碼。

閱讀更多有關例外狀況的資訊,包括堆疊追蹤、rethrow,以及ErrorException之間的差異。

重要概念

#

當您持續學習 Dart 語言時,請記住這些事實和概念

  • 您可以放入變數中的所有內容都是物件,而每個物件都是類別的實例。甚至數字、函式和null都是物件。除了null (如果您啟用健全的 Null 安全性),所有物件都繼承自Object類別。

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

  • 如果您啟用 null safety,變數不能包含 null,除非您說可以。您可以透過在變數類型的結尾加上問號 (?) 來使變數可為 null。例如,類型為 int? 的變數可能是整數,也可能是 null。如果您知道某個表達式絕不會評估為 null,但 Dart 不認同,您可以新增 ! 來斷言它不是 null(如果它是,則會擲出例外)。範例:int x = nullableButNotNullInt!

  • 當您想要明確表示允許任何類型時,請使用類型 Object?(如果您已啟用 null safety)、Object,或者——如果您必須將類型檢查延後到執行階段——特殊類型 dynamic

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

  • Dart 支援頂層函式(例如 main()),以及與類別或物件相關聯的函式(分別為靜態實例方法)。您還可以在函式內建立函式(巢狀區域函式)。

  • 類似地,Dart 支援頂層變數,以及與類別或物件相關聯的變數(靜態和實例變數)。實例變數有時稱為欄位屬性

  • 與 Java 不同,Dart 沒有 publicprotectedprivate 關鍵字。如果識別碼以底線 (_) 開頭,則表示其函式庫為私有的。有關詳細資訊,請參閱 函式庫和匯入

  • 識別碼可以字母或底線 (_) 開頭,後接這些字元加上數字的任意組合。

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

  • Dart 工具可以報告兩種問題:警告錯誤。警告只是表示您的程式碼可能無法運作,但不會阻止您的程式執行。錯誤可以是編譯時期或執行時期。編譯時期錯誤會阻止程式執行;執行時期錯誤會導致在程式執行時引發例外狀況

其他資源

#

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