內容

dart:core 函式庫 (API 參考) 提供一組精簡但重要的內建功能。此函式庫會自動匯入每個 Dart 程式。

列印到主控台

#

頂層 print() 方法會接收單一參數 (任何物件),並在主控台中顯示該物件的字串值 (由 toString() 傳回)。

dart
print(anObject);
print('I drink $tea.');

如需有關基本字串和 toString() 的更多資訊,請參閱語言導覽中的 字串

數字

#

dart:core 函式庫定義了 num、int 和 double 類別,這些類別有一些用於處理數字的基本公用程式。

您可以使用 int 和 double 的 parse() 方法,分別將字串轉換為整數或浮點數

dart
assert(int.parse('42') == 42);
assert(int.parse('0x42') == 66);
assert(double.parse('0.50') == 0.5);

或使用 num 的 parse() 方法,如果可能,它會建立整數,否則會建立浮點數

dart
assert(num.parse('42') is int);
assert(num.parse('0x42') is int);
assert(num.parse('0.50') is double);

若要指定整數的基底,請新增 radix 參數

dart
assert(int.parse('42', radix: 16) == 66);

使用 toString() 方法將 int 或 double 轉換為字串。若要指定小數點右邊的位數,請使用 toStringAsFixed(). 若要指定字串中的有效位數,請使用 toStringAsPrecision():

dart
// Convert an int to a string.
assert(42.toString() == '42');

// Convert a double to a string.
assert(123.456.toString() == '123.456');

// Specify the number of digits after the decimal.
assert(123.456.toStringAsFixed(2) == '123.46');

// Specify the number of significant figures.
assert(123.456.toStringAsPrecision(2) == '1.2e+2');
assert(double.parse('1.2e+2') == 120.0);

如需更多資訊,請參閱 int, double,num 的 API 文件。另請參閱 dart:math 區段

字串和正規表示式

#

Dart 中的字串是 UTF-16 編碼單位的不可變序列。語言導覽中提供了更多有關 字串 的資訊。您可以使用正規表示式 (RegExp 物件) 在字串中搜尋和取代字串的部分內容。

字串類別定義了諸如 split()contains()startsWith()endsWith() 等方法。

在字串內搜尋

#

您可以在字串中找到特定位置,以及檢查字串是否以特定模式開頭或結尾。例如

dart
// Check whether a string contains another string.
assert('Never odd or even'.contains('odd'));

// Does a string start with another string?
assert('Never odd or even'.startsWith('Never'));

// Does a string end with another string?
assert('Never odd or even'.endsWith('even'));

// Find the location of a string inside a string.
assert('Never odd or even'.indexOf('odd') == 6);

從字串中萃取資料

#

您可以分別將個別字元從字串中取得為字串或整數。準確來說,您實際上取得個別 UTF-16 編碼單位;高編號字元(例如高音譜號符號 ('\u{1D11E}'))是兩個編碼單位。

您也可以擷取子字串或將字串拆分為子字串清單

dart
// Grab a substring.
assert('Never odd or even'.substring(6, 9) == 'odd');

// Split a string using a string pattern.
var parts = 'progressive web apps'.split(' ');
assert(parts.length == 3);
assert(parts[0] == 'progressive');

// Get a UTF-16 code unit (as a string) by index.
assert('Never odd or even'[0] == 'N');

// Use split() with an empty string parameter to get
// a list of all characters (as Strings); good for
// iterating.
for (final char in 'hello'.split('')) {
  print(char);
}

// Get all the UTF-16 code units in the string.
var codeUnitList = 'Never odd or even'.codeUnits.toList();
assert(codeUnitList[0] == 78);

::: 在許多情況下,您希望使用 Unicode 字形叢集,而不是純編碼單位。這些字元是使用者感知到的字元(例如,「🇬🇧」是一個使用者感知的字元,但有幾個 UTF-16 編碼單位)。對於這一點,Dart 團隊提供了 characters 套件。 ::

轉換為大寫或小寫

#

您可以輕鬆地將字串轉換為其大寫和小寫變體

dart
// Convert to uppercase.
assert('web apps'.toUpperCase() == 'WEB APPS');

// Convert to lowercase.
assert('WEB APPS'.toLowerCase() == 'web apps');

修剪和空字串

#

使用 trim() 移除所有前導和尾隨空白。若要檢查字串是否為空(長度為零),請使用 isEmpty

dart
// Trim a string.
assert('  hello  '.trim() == 'hello');

// Check whether a string is empty.
assert(''.isEmpty);

// Strings with only white space are not empty.
assert('  '.isNotEmpty);

取代字串的一部分

#

字串是不可變物件,這表示您可以建立它們,但無法變更它們。如果您仔細查看 字串 API 參考,您會注意到沒有任何方法實際上會變更字串的狀態。例如,方法 replaceAll() 會傳回一個新的字串,而不會變更原始字串

dart
var greetingTemplate = 'Hello, NAME!';
var greeting = greetingTemplate.replaceAll(RegExp('NAME'), 'Bob');

// greetingTemplate didn't change.
assert(greeting != greetingTemplate);

建立字串

#

若要以程式化方式產生字串,您可以使用 StringBuffer。StringBuffer 只有在呼叫 toString() 之後才會產生新的字串物件。writeAll() 方法有一個選用的第二個參數,讓您可以指定分隔符號,在本例中為空白。

dart
var sb = StringBuffer();
sb
  ..write('Use a StringBuffer for ')
  ..writeAll(['efficient', 'string', 'creation'], ' ')
  ..write('.');

var fullString = sb.toString();

assert(fullString == 'Use a StringBuffer for efficient string creation.');

正規表示式

#

RegExp 類別提供了與 JavaScript 正規表示式相同的功能。使用正規表示式進行字串的有效搜尋和模式比對。

dart
// Here's a regular expression for one or more digits.
var numbers = RegExp(r'\d+');

var allCharacters = 'llamas live fifteen to twenty years';
var someDigits = 'llamas live 15 to 20 years';

// contains() can use a regular expression.
assert(!allCharacters.contains(numbers));
assert(someDigits.contains(numbers));

// Replace every match with another string.
var exedOut = someDigits.replaceAll(numbers, 'XX');
assert(exedOut == 'llamas live XX to XX years');

您也可以直接使用 RegExp 類別。Match 類別提供對正規表示式比對的存取。

dart
var numbers = RegExp(r'\d+');
var someDigits = 'llamas live 15 to 20 years';

// Check whether the reg exp has a match in a string.
assert(numbers.hasMatch(someDigits));

// Loop through all matches.
for (final match in numbers.allMatches(someDigits)) {
  print(match.group(0)); // 15, then 20
}

更多資訊

#

請參閱 字串 API 參考 以取得方法的完整清單。另請參閱 StringBufferPatternRegExpMatch 的 API 參考。

集合

#

Dart 附帶核心集合 API,其中包含清單、集合和對應的類別。

清單

#

如同語言導覽所示,你可以使用字面值來建立和初始化 清單。或者,使用其中一個清單建構函式。清單類別也定義了數個方法,用於將項目新增到清單中,以及從清單中移除項目。

dart
// Create an empty list of strings.
var grains = <String>[];
assert(grains.isEmpty);

// Create a list using a list literal.
var fruits = ['apples', 'oranges'];

// Add to a list.
fruits.add('kiwis');

// Add multiple items to a list.
fruits.addAll(['grapes', 'bananas']);

// Get the list length.
assert(fruits.length == 5);

// Remove a single item.
var appleIndex = fruits.indexOf('apples');
fruits.removeAt(appleIndex);
assert(fruits.length == 4);

// Remove all elements from a list.
fruits.clear();
assert(fruits.isEmpty);

// You can also create a List using one of the constructors.
var vegetables = List.filled(99, 'broccoli');
assert(vegetables.every((v) => v == 'broccoli'));

使用 indexOf() 來尋找清單中物件的索引

dart
var fruits = ['apples', 'oranges'];

// Access a list item by index.
assert(fruits[0] == 'apples');

// Find an item in a list.
assert(fruits.indexOf('apples') == 0);

使用 sort() 方法來對清單進行排序。你可以提供一個比較兩個物件的排序函式。此排序函式必須傳回 < 0 表示較小、0 表示相同,以及 > 0 表示較大。下列範例使用 compareTo(),由 Comparable 定義,並由字串實作。

dart
var fruits = ['bananas', 'apples', 'oranges'];

// Sort a list.
fruits.sort((a, b) => a.compareTo(b));
assert(fruits[0] == 'apples');

清單是參數化類型 (泛型),因此你可以指定清單應包含的類型

dart
// This list should contain only strings.
var fruits = <String>[];

fruits.add('apples');
var fruit = fruits[0];
assert(fruit is String);
✗ 靜態分析:失敗dart
fruits.add(5); // Error: 'int' can't be assigned to 'String'

請參閱 清單 API 參考,以取得方法的完整清單。

集合

#

Dart 中的集合是唯一項目的無序集合。由於集合是無序的,因此你無法透過索引 (位置) 來取得集合的項目。

dart
// Create an empty set of strings.
var ingredients = <String>{};

// Add new items to it.
ingredients.addAll(['gold', 'titanium', 'xenon']);
assert(ingredients.length == 3);

// Adding a duplicate item has no effect.
ingredients.add('gold');
assert(ingredients.length == 3);

// Remove an item from a set.
ingredients.remove('gold');
assert(ingredients.length == 2);

// You can also create sets using
// one of the constructors.
var atomicNumbers = Set.from([79, 22, 54]);

使用 contains()containsAll() 來檢查集合中是否有一個或多個物件

dart
var ingredients = Set<String>();
ingredients.addAll(['gold', 'titanium', 'xenon']);

// Check whether an item is in the set.
assert(ingredients.contains('titanium'));

// Check whether all the items are in the set.
assert(ingredients.containsAll(['titanium', 'xenon']));

交集是項目在兩個其他集合中的集合。

dart
var ingredients = Set<String>();
ingredients.addAll(['gold', 'titanium', 'xenon']);

// Create the intersection of two sets.
var nobleGases = Set.from(['xenon', 'argon']);
var intersection = ingredients.intersection(nobleGases);
assert(intersection.length == 1);
assert(intersection.contains('xenon'));

請參閱 集合 API 參考,以取得方法的完整清單。

對應

#

映射 (通常稱為字典或雜湊) 是鍵值對的無序集合。映射會將鍵與某個值關聯,以便於擷取。與 JavaScript 不同,Dart 物件不是映射。

你可以使用簡潔的字面值語法來宣告映射,或者你可以使用傳統的建構函式

dart
// Maps often use strings as keys.
var hawaiianBeaches = {
  'Oahu': ['Waikiki', 'Kailua', 'Waimanalo'],
  'Big Island': ['Wailea Bay', 'Pololu Beach'],
  'Kauai': ['Hanalei', 'Poipu']
};

// Maps can be built from a constructor.
var searchTerms = Map();

// Maps are parameterized types; you can specify what
// types the key and value should be.
var nobleGases = Map<int, String>();

你可以使用方括號語法來新增、取得和設定映射項目。使用 remove() 從映射中移除鍵及其值。

dart
var nobleGases = {54: 'xenon'};

// Retrieve a value with a key.
assert(nobleGases[54] == 'xenon');

// Check whether a map contains a key.
assert(nobleGases.containsKey(54));

// Remove a key and its value.
nobleGases.remove(54);
assert(!nobleGases.containsKey(54));

你可以從 map 中擷取所有值或所有鍵

dart
var hawaiianBeaches = {
  'Oahu': ['Waikiki', 'Kailua', 'Waimanalo'],
  'Big Island': ['Wailea Bay', 'Pololu Beach'],
  'Kauai': ['Hanalei', 'Poipu']
};

// Get all the keys as an unordered collection
// (an Iterable).
var keys = hawaiianBeaches.keys;

assert(keys.length == 3);
assert(Set.from(keys).contains('Oahu'));

// Get all the values as an unordered collection
// (an Iterable of Lists).
var values = hawaiianBeaches.values;
assert(values.length == 3);
assert(values.any((v) => v.contains('Waikiki')));

若要檢查 map 是否包含鍵,請使用 containsKey()。由於 map 值可以為 null,因此你不能僅取得鍵的值並檢查是否為 null 來判斷鍵是否存在。

dart
var hawaiianBeaches = {
  'Oahu': ['Waikiki', 'Kailua', 'Waimanalo'],
  'Big Island': ['Wailea Bay', 'Pololu Beach'],
  'Kauai': ['Hanalei', 'Poipu']
};

assert(hawaiianBeaches.containsKey('Oahu'));
assert(!hawaiianBeaches.containsKey('Florida'));

當你想要將值指定給鍵,但前提是該鍵尚未存在於 map 中時,請使用 putIfAbsent() 方法。你必須提供傳回值的函式。

dart
var teamAssignments = <String, String>{};
teamAssignments.putIfAbsent('Catcher', () => pickToughestKid());
assert(teamAssignments['Catcher'] != null);

請參閱 Map API 參考,以取得方法的完整清單。

常見的集合方法

#

清單、集合和 Map 共享許多集合中找到的共用功能。這些共用功能中的一些是由清單和集合實作的 Iterable 類別所定義。

使用 isEmptyisNotEmpty 來檢查清單、集合或 Map 是否有項目

dart
var coffees = <String>[];
var teas = ['green', 'black', 'chamomile', 'earl grey'];
assert(coffees.isEmpty);
assert(teas.isNotEmpty);

若要將函式套用至清單、集合或 Map 中的每個項目,你可以使用 forEach()

dart
var teas = ['green', 'black', 'chamomile', 'earl grey'];

teas.forEach((tea) => print('I drink $tea'));

當你對 map 呼叫 forEach() 時,你的函式必須採用兩個引數(鍵和值)

dart
hawaiianBeaches.forEach((k, v) {
  print('I want to visit $k and swim at $v');
  // I want to visit Oahu and swim at
  // [Waikiki, Kailua, Waimanalo], etc.
});

Iterable 提供 map() 方法,它會在單一物件中提供所有結果

dart
var teas = ['green', 'black', 'chamomile', 'earl grey'];

var loudTeas = teas.map((tea) => tea.toUpperCase());
loudTeas.forEach(print);

若要強制你的函式立即對每個項目呼叫,請使用 map().toList()map().toSet()

dart
var loudTeas = teas.map((tea) => tea.toUpperCase()).toList();

使用 Iterable 的 where() 方法來取得符合條件的所有項目。使用 Iterable 的 any()every() 方法來檢查某些或所有項目是否符合條件。

dart
var teas = ['green', 'black', 'chamomile', 'earl grey'];

// Chamomile is not caffeinated.
bool isDecaffeinated(String teaName) => teaName == 'chamomile';

// Use where() to find only the items that return true
// from the provided function.
var decaffeinatedTeas = teas.where((tea) => isDecaffeinated(tea));
// or teas.where(isDecaffeinated)

// Use any() to check whether at least one item in the
// collection satisfies a condition.
assert(teas.any(isDecaffeinated));

// Use every() to check whether all the items in a
// collection satisfy a condition.
assert(!teas.every(isDecaffeinated));

請參閱 Iterable API 參考,以及 清單集合Map 的 API 參考,以取得方法的完整清單。

URI

#

Uri 類別 提供函式,用於對字串編碼和解碼,以便在 URI 中使用(你可能將其稱為 URL)。這些函式會處理對 URI 來說很特殊的字元,例如 &=。Uri 類別還會剖析 URI 的組成部分(主機、埠、架構等)並公開這些組成部分。

編碼和解碼完全限定的 URI

#

要對字元進行編碼和解碼,除了 URI 中具有特殊意義的字元(例如 /:&#),請使用 encodeFull()decodeFull() 方法。這些方法適用於編碼或解碼完全限定的 URI,並保留 URI 特殊字元。

dart
var uri = 'https://example.org/api?foo=some message';

var encoded = Uri.encodeFull(uri);
assert(encoded == 'https://example.org/api?foo=some%20message');

var decoded = Uri.decodeFull(encoded);
assert(uri == decoded);

請注意,只有 somemessage 之間的空格已編碼。

編碼和解碼 URI 組件

#

要編碼和解碼字串中所有在 URI 中具有特殊意義的字元,包括(但不限於)/&:,請使用 encodeComponent()decodeComponent() 方法。

dart
var uri = 'https://example.org/api?foo=some message';

var encoded = Uri.encodeComponent(uri);
assert(
    encoded == 'https%3A%2F%2Fexample.org%2Fapi%3Ffoo%3Dsome%20message');

var decoded = Uri.decodeComponent(encoded);
assert(uri == decoded);

請注意,每個特殊字元都已編碼。例如,/ 編碼為 %2F

剖析 URI

#

如果您有 Uri 物件或 URI 字串,可以使用 Uri 欄位(例如 path)取得其部分。要從字串建立 Uri,請使用 parse() 靜態方法

dart
var uri = Uri.parse('https://example.org:8080/foo/bar#frag');

assert(uri.scheme == 'https');
assert(uri.host == 'example.org');
assert(uri.path == '/foo/bar');
assert(uri.fragment == 'frag');
assert(uri.origin == 'https://example.org:8080');

請參閱 Uri API 參考,以取得更多您可以取得的 URI 組件。

建立 URI

#

您可以使用 Uri() 建構函式從個別部分建立 URI

dart
var uri = Uri(
    scheme: 'https',
    host: 'example.org',
    path: '/foo/bar',
    fragment: 'frag',
    queryParameters: {'lang': 'dart'});
assert(uri.toString() == 'https://example.org/foo/bar?lang=dart#frag');

如果您不需要指定片段,要建立具有 http 或 https 架構的 URI,您可以改用 Uri.httpUri.https 工廠建構函式

dart
var httpUri = Uri.http('example.org', '/foo/bar', {'lang': 'dart'});
var httpsUri = Uri.https('example.org', '/foo/bar', {'lang': 'dart'});

assert(httpUri.toString() == 'http://example.org/foo/bar?lang=dart');
assert(httpsUri.toString() == 'https://example.org/foo/bar?lang=dart');

日期和時間

#

DateTime 物件是時間點。時區為 UTC 或當地時區。

您可以使用多個建構函式和方法建立 DateTime 物件

dart
// Get the current date and time.
var now = DateTime.now();

// Create a new DateTime with the local time zone.
var y2k = DateTime(2000); // January 1, 2000

// Specify the month and day.
y2k = DateTime(2000, 1, 2); // January 2, 2000

// Specify the date as a UTC time.
y2k = DateTime.utc(2000); // 1/1/2000, UTC

// Specify a date and time in ms since the Unix epoch.
y2k = DateTime.fromMillisecondsSinceEpoch(946684800000, isUtc: true);

// Parse an ISO 8601 date in the UTC time zone.
y2k = DateTime.parse('2000-01-01T00:00:00Z');

// Create a new DateTime from an existing one, adjusting just some properties:
var sameTimeLastYear = now.copyWith(year: now.year - 1);

日期的 millisecondsSinceEpoch 屬性會傳回自「Unix 紀元」(1970 年 1 月 1 日 UTC)以來的毫秒數

dart
// 1/1/2000, UTC
var y2k = DateTime.utc(2000);
assert(y2k.millisecondsSinceEpoch == 946684800000);

// 1/1/1970, UTC
var unixEpoch = DateTime.utc(1970);
assert(unixEpoch.millisecondsSinceEpoch == 0);

使用 Duration 類別計算兩個日期之間的差額,並將日期向前或向後移動

dart
var y2k = DateTime.utc(2000);

// Add one year.
var y2001 = y2k.add(const Duration(days: 366));
assert(y2001.year == 2001);

// Subtract 30 days.
var december2000 = y2001.subtract(const Duration(days: 30));
assert(december2000.year == 2000);
assert(december2000.month == 12);

// Calculate the difference between two dates.
// Returns a Duration object.
var duration = y2001.difference(y2k);
assert(duration.inDays == 366); // y2k was a leap year.

如需方法的完整清單,請參閱 DateTimeDuration 的 API 參考。

公用程式類別

#

核心函式庫包含各種實用類別,可用於排序、對應值和反覆運算。

比較物件

#

實作 Comparable 介面以表示物件可以與另一個物件進行比較,通常用於排序。compareTo() 方法會傳回 < 0 表示較、0 表示相同和 > 0 表示較

dart
class Line implements Comparable<Line> {
  final int length;
  const Line(this.length);

  @override
  int compareTo(Line other) => length - other.length;
}

void main() {
  var short = const Line(1);
  var long = const Line(100);
  assert(short.compareTo(long) < 0);
}

實作映射鍵

#

Dart 中的每個物件都會自動提供一個整數雜湊碼,因此可以用作字典中的金鑰。不過,您可以覆寫 hashCode getter 以產生自訂雜湊碼。如果您這樣做,您可能還想覆寫 == 算子。相等的物件 (透過 ==) 必須有相同的雜湊碼。雜湊碼不一定要是唯一的,但應該要分佈良好。

dart
class Person {
  final String firstName, lastName;

  Person(this.firstName, this.lastName);

  // Override hashCode using the static hashing methods
  // provided by the `Object` class.
  @override
  int get hashCode => Object.hash(firstName, lastName);

  // You should generally implement operator `==` if you
  // override `hashCode`.
  @override
  bool operator ==(Object other) {
    return other is Person &&
        other.firstName == firstName &&
        other.lastName == lastName;
  }
}

void main() {
  var p1 = Person('Bob', 'Smith');
  var p2 = Person('Bob', 'Smith');
  var p3 = 'not a person';
  assert(p1.hashCode == p2.hashCode);
  assert(p1 == p2);
  assert(p1 != p3);
}

反覆運算

#

IterableIterator 類別支援對一系列值的順序存取。若要練習使用這些集合,請遵循 Iterable 集合程式碼實驗

如果您建立一個類別可以提供用於 for-in 迴圈的 Iterator,請 (如果可能) 延伸或實作 Iterable。實作 Iterator 以定義實際的迭代能力。

dart
class Process {
  // Represents a process...
}

class ProcessIterator implements Iterator<Process> {
  @override
  Process get current => ...
  @override
  bool moveNext() => ...
}

// A mythical class that lets you iterate through all
// processes. Extends a subclass of [Iterable].
class Processes extends IterableBase<Process> {
  @override
  final Iterator<Process> iterator = ProcessIterator();
}

void main() {
  // Iterable objects can be used with for-in.
  for (final process in Processes()) {
    // Do something with the process.
  }
}

例外

#

Dart 核心函式庫定義許多常見的例外和錯誤。例外被視為您可以預先規劃並捕捉的狀況。錯誤是您不預期或規劃的狀況。

最常見的幾個錯誤為

NoSuchMethodError
當接收物件 (可能是 null) 未實作方法時擲出。
ArgumentError
當方法遇到意外引數時可能會擲出。

擲出應用程式特定的例外狀況是表示發生錯誤的常見方式。您可以透過實作 Exception 介面來定義自訂例外狀況

dart
class FooException implements Exception {
  final String? msg;

  const FooException([this.msg]);

  @override
  String toString() => msg ?? 'FooException';
}

如需更多資訊,請參閱 例外狀況(在語言導覽中)和 例外狀況 API 參考。

弱參照和完成處理常式

#

Dart 是一種 垃圾回收 語言,表示任何未被參照的 Dart 物件都可以由垃圾回收器處置。在某些涉及原生資源或無法修改目標物件的場景中,這種預設行為可能不可取。

WeakReference 會儲存對目標物件的參照,而不會影響垃圾回收器如何回收它。另一個選項是使用 Expando 將屬性新增到物件。

Finalizer 可用於在物件不再被參照後執行回呼函式。不過,無法保證執行此回呼。

NativeFinalizer 提供更強的保證,可使用 dart:ffi 與原生程式碼互動;在物件不再被參照後,其回呼會被呼叫至少一次。此外,它可被用於關閉原生資源,例如資料庫連線或開啟檔案。

若要確保物件不會過早被垃圾回收和完成,類別可以實作 Finalizable 介面。當一個區域變數為 Finalizable 時,它不會被垃圾回收,直到宣告它的程式碼區塊結束。