Dart 簡介
本頁面透過 Dart 語言主要功能的示例,對其進行簡要介紹。
要了解有關 Dart 語言的更多資訊,請訪問左側選單中 語言 下列出的深入的各個主題頁面。
要了解 Dart 的核心庫,請檢視核心庫文件。你也可以檢視Dart 速查表,以獲得更具互動性的介紹。
Hello World
#每個應用都需要頂級的 main() 函式,程式的執行從這裡開始。沒有顯式返回值的函式擁有 void 返回型別。要在控制檯顯示文字,你可以使用頂級的 print() 函式
void main() {
print('Hello, World!');
}閱讀更多關於 Dart 中main() 函式的資訊,包括命令列引數的可選引數。
變數
#即使在型別安全的 Dart 程式碼中,你也可以使用 var 宣告大多數變數,而無需顯式指定它們的型別。由於型別推斷,這些變數的型別由它們的初始值決定
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 中變數的資訊,包括預設值、final 和 const 關鍵字以及靜態型別。
控制流語句
#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 中控制流語句的資訊,包括break 和 continue、switch 和 case 以及assert。
函式
#我們建議指定每個函式的引數和返回值的型別
int fibonacci(int n) {
if (n == 0 || n == 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
var result = fibonacci(20);=>(箭頭)的簡寫語法對於只包含單個語句的函式非常方便。這種語法在將匿名函式作為引數傳遞時特別有用
flybyObjects.where((name) => name.contains('turn')).forEach(print);除了展示匿名函式(where() 的引數)之外,此程式碼還展示了你可以將函式用作引數:頂級的 print() 函式是 forEach() 的引數。
閱讀更多關於 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。
// 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 中庫和可見性的資訊,包括庫字首、show 和 hide,以及透過 deferred 關鍵字進行的延遲載入。
類
#這是一個包含三個屬性、兩個建構函式和一個方法的類的示例。其中一個屬性不能直接設定,因此它是使用 getter 方法(而不是變數)定義的。該方法使用字串插值來在字串字面量中列印變數的字串等效內容。
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 類
var voyager = Spacecraft('Voyager I', DateTime(1977, 9, 5));
voyager.describe();
var voyager3 = Spacecraft.unlaunched('Voyager III');
voyager3.describe();閱讀更多關於 Dart 中類的資訊,包括初始化列表、可選的 new 和 const、重定向建構函式、factory 建構函式、getter、setter 等等。
列舉
#列舉是一種列舉預定義的值集或例項的方式,它確保該型別不會有其他例項。
這是一個簡單的 enum 的示例,它定義了一個預定義的行星型別列表
enum PlanetType { terrestrial, gas, ice }這是一個增強型列舉宣告的示例,它是一個描述行星的類,帶有一組定義的常量例項,即我們太陽系中的行星。
/// 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 列舉
final yourPlanet = Planet.earth;
if (!yourPlanet.isGiant) {
print('Your planet is not a "giant planet".');
}閱讀更多關於 Dart 中列舉的資訊,包括增強型列舉要求、自動引入的屬性、訪問列舉值名稱、switch 語句支援等等。
繼承
#Dart 支援單繼承。
class Orbiter extends Spacecraft {
double altitude;
Orbiter(super.name, DateTime super.launchDate, this.altitude);
}閱讀更多關於擴充套件類、可選的 @override 註解等等。
混入
#混入是一種在多個類層次結構中重用程式碼的方式。以下是混入宣告
mixin Piloted {
int astronauts = 1;
void describeCrew() {
print('Number of astronauts: $astronauts');
}
}要將混入的功能新增到類中,只需用混入擴充套件該類即可。
class PilotedCraft extends Spacecraft with Piloted {
// ···
}PilotedCraft 現在擁有 astronauts 欄位和 describeCrew() 方法。
閱讀更多關於混入的資訊。
介面和抽象類
#所有類都隱式定義一個介面。因此,你可以實現任何類。
class MockSpaceship implements Spacecraft {
// ···
}閱讀更多關於隱式介面或顯式interface 關鍵字的資訊。
你可以建立一個抽象類,供具體類擴充套件(或實現)。抽象類可以包含抽象方法(帶有空方法體)。
abstract class Describable {
void describe();
void describeWithEmphasis() {
print('=========');
describe();
print('=========');
}
}任何擴充套件 Describable 的類都具有 describeWithEmphasis() 方法,該方法呼叫擴充套件者對 describe() 的實現。
閱讀更多關於抽象類和方法的資訊。
非同步
#透過使用 async 和 await,避免回撥地獄,並使你的程式碼更具可讀性。
const oneSecond = Duration(seconds: 1);
// ···
Future<void> printWithDelay(String message) async {
await Future.delayed(oneSecond);
print(message);
}上面的方法等效於
Future<void> printWithDelay(String message) {
return Future.delayed(oneSecond).then((_) {
print(message);
});
}如下一個示例所示,async 和 await 有助於使非同步程式碼易於閱讀。
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*,它為你提供了一種良好、可讀的方式來構建流。
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 函式、Future、Stream 和非同步迴圈(await for)。
異常
#要丟擲異常,請使用 throw
if (astronauts == 0) {
throw StateError('No astronauts.');
}要捕獲異常,請使用帶有 on 或 catch(或兩者)的 try 語句
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 以及 Error 和 Exception 之間的區別。
重要概念
#隨著你繼續學習 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 沒有
public、protected和private關鍵字。如果識別符號以(_)下劃線開頭,則它是其庫的私有成員。有關詳細資訊,請參閱庫與匯入。識別符號可以以字母或下劃線 (
_) 開頭,後跟這些字元和數字的任意組合。Dart 既有表示式(具有執行時值),也有語句(不具有)。例如,條件表示式
condition ? expr1 : expr2的值為expr1或expr2。將其與沒有值的if-else 語句進行比較。語句通常包含一個或多個表示式,但表示式不能直接包含語句。Dart 工具可以報告兩種問題:警告和錯誤。警告只是表明你的程式碼可能無法工作,但它們不會阻止你的程式執行。錯誤可以是編譯時錯誤或執行時錯誤。編譯時錯誤會完全阻止程式碼執行;執行時錯誤會導致程式碼執行時引發異常。
附加資源
#你可以在核心庫文件和Dart API 參考中找到更多文件和程式碼示例。本網站的程式碼遵循Dart 風格指南中的約定。