Dart官方文檔翻譯(一)(Dart之旅)

這篇文章將會向你展示如何使用Dart的每一個知識點,包括變量,操作符,類,類庫,但這是在你已經有一個其他語言的編碼經驗的前提下。
為了學習Dart更多關于Dart的核心類庫,請查看A Tour of the Dart Libraries,當你想知道更多語言特征,挺查閱Dart language specification

你可以通過DartPad 來嘗試運行Dart代碼:Open DartPad

一個基本的Dart程序

// Define a function.
printInteger(int aNumber) {
  print('The number is $aNumber.'); // Print to console.
}

// This is where the app starts executing.
main() {
  var number = 42; // Declare and initialize a variable.
  printInteger(number); // Call a function.
}

以下是此程序使用的適用于所有(或幾乎所有)Dart應用程序的內容:

// This is a comment.

單行注釋。Dart還支持多行和文檔注釋。有關詳情,請參閱注釋

int

整數(shù)類型。一些其他的內置類型String,Listbool

42

一個整數(shù)字面值,這是一個編譯時常量。

print()

一個方便的輸出函數(shù)。

'...' (or "...")

字符串字面值。

$variableName(或)${expression}

字符串插值:包括字符串字面值內部的變量或表達式的字符串。有關更多信息,請參閱 字符串。

main()

一個特殊的頂級(top)的必須的(requared)app應用的入口函數(shù),有關更多信息,請參閱 main()函數(shù)。

var

一種聲明變量而不指定其類型的方法。

重要的概念

當您了解Dart語言時,請記住以下事實和概念:

  • 變量所指向的所有值都是對象,每個對象都是一個的實例。數(shù)字,函數(shù)(函數(shù)也是一個變量)和 null對象等。所有對象都繼承自Object類。
  • 盡管Dart是強類型的,但類型聲明是可選的,因為Dart可以推斷類型。在上面的代碼中,number 推斷為類型int。如果要明確說明不需要任何類型,請 使用特殊類型dynamic。
  • Dart支持泛型類型,如List<int>(整數(shù)List)或List<dynamic>(任何類型的對象List)。
  • Dart支持頂級函數(shù)(例如main()),以及綁定到類或對象的函數(shù)(分別是靜態(tài)和實例方法)。您還可以在函數(shù)內創(chuàng)建函數(shù)(嵌套函數(shù)或本地函數(shù))。
  • 類似地,Dart支持頂級變量,以及綁定到類或對象的變量(靜態(tài)和實例變量)。實例變量有時稱為字段或屬性。
  • 與Java,Dart不具備關鍵字public,protectedprivate。如果標識符以下劃線(_)開頭,則它對其庫是私有的。有關詳細信息,請參閱 庫和可見性。
  • 標識符可以以字母或下劃線(_)開頭,后跟這些字符加數(shù)字的任意組合。
  • Dart可以使用表達式(具有運行時值)和 語句(不具有)。例如,條件表達式 condition ? expr1 : expr2的值為expr1expr2。將其與if-else語句進行比較,語句沒有任何值。語句通常包含一個或多個表達式,但表達式不能直接包含語句。
  • Dart工具可以報告兩種問題:警告錯誤。警告只是表明您的代碼可能無法正常工作,但它們不會阻止您的程序執(zhí)行。錯誤可以是編譯時或運行時。編譯時錯誤會阻止代碼執(zhí)行; 運行時錯誤導致 代碼執(zhí)行時引發(fā)異常。

關鍵字

下表列出了Dart語言的關鍵字:

abstract 2 dynamic 2 implements 2 show 1
as 2 else import 2 static 2
assert enum in super
async 1 export 2 interface 2 switch
await 3 extends is sync 1
break external 2 library 2 this
case factory 2 mixin 2 throw
catch false new true
class final null try
const finally on 1 typedef 2
continue for operator 2 var
covariant 2 Function 2 part 2 void
default get 2 rethrow while
deferred 2 hide 1 return with
do if set 2 yield 3

避免使用這些單詞作為標識符。但是,如有必要,標有上標的關鍵字可以是標識符:

  • 帶有上標1的單詞是上下文關鍵字,僅在特定位置具有含義。
  • 帶有上標2的單詞是內置標識符。為了簡化將JavaScript代碼移植到Dart的任務,這些關鍵字在大多數(shù)地方都是有效的標識符,但它們不能用作類或類型名稱,也不能用作導入前綴。
  • 帶有上標3的單詞是與Dart 1.0發(fā)布后添加的異步支持相關的更新,有限的保留字。不能使用awaityield作為任何函數(shù)體中的標識符標記async,async*sync*。
    表中的所有其他單詞都是保留字,不能是標識符。

變量

這是創(chuàng)建變量并初始化它的示例:

var name = 'Bob' ; 

變量存儲引用。名為name的變量指向String值為“Bob” 的對象。
name推斷變量的類型String,但您可以通過指定它來更改該類型。如果對象不限于單一類型,請按照設計準則指定Objectdynamic類型 。

dynamic name = 'Bob' ; 

另一種選擇是顯式聲明類型:

String name = 'Bob' ; 

注意: 此頁面遵循 風格指南建議 使用var,而不是指定類型,用于局部變量。

默認值

未初始化的變量的初始值為null。即使是具有數(shù)字類型的變量最初也是null,因為數(shù)字 - 就像Dart中的其他所有都是對象。

int lineCount ; 
assert (lineCount == null );

注意:生產環(huán)境代碼中將忽略assert() 調用。在開發(fā)期間, 除非條件為真,否則拋出異常。有關詳細信息,請參閱斷言。

Final and const

如果您從未打算更改變量,請使用final或const代替var或替代類型。最終變量只能設置一次; const變量是編譯時常量。(Const變量是隱式final的。)final的頂級或類變量在第一次使用時被初始化。
以下是創(chuàng)建和設置最終變量的示例:

final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';

您無法更改最終變量的值:

name = 'Alice' ; //錯誤:最終變量只能設置一次。  

使用const為您要為變量的編譯時間常數(shù)。如果const變量在類級別,請聲明為static const。在聲明變量的地方,將值設置為編譯時常量,例如數(shù)字或字符串字面值,const變量或對常數(shù)進行算術運算的結果:

const bar = 1000000; // 壓力單位 (dynes/cm2)
const double atm = 1.01325 * bar; // 標準大氣壓

該const關鍵字不只是聲明常數(shù)變量。您還可以使用它來創(chuàng)建常量值,以及聲明創(chuàng)建常量值的構造函數(shù)。任何變量都可以具有常量值。

var foo = const [];
final bar = const [];
const baz = []; //相當于`const []`  

您可以省略聲明const的初始化表達式,如上所述。有關詳細信息,請參閱不要冗余地使用constconst``baz
您可以更改非final,非const變量的值,即使它曾經有一個const值:

foo = [1, 2, 3]; // Was const []

您無法更改const變量的值:

baz = [ 42 ]; //錯誤:無法為常量變量賦值。  

有關使用const創(chuàng)建常量值的更多信息,請參閱 Lists,MapsClasses

內置類型

Dart語言特別支持以下類型:

  • numbers
  • strings
  • booleans
  • lists (also known as arrays)
  • sets
  • maps
  • runes (for expressing Unicode characters in a string)
  • symbols
    您可以使用字面值初始化任何這些特殊類型的對象。例如,'this is a string'是一個字符串字面值,true是一個布爾字面值。
    因為Dart中的每個變量都引用一個對象 - 一個類的實例 - 您通常可以使用構造函數(shù)來初始化變量。一些內置類型有自己的構造函數(shù)。例如,您可以使用Map()構造函數(shù)來創(chuàng)建Map。

Numbers

Dart 數(shù)字有兩種形式:
int
整數(shù)值不大于64位,具體取決于平臺。在Dart VM上,值可以是-2 63到2 63 - 1.編譯為JavaScript的Dart使用 JavaScript編號, 允許從-2 53到2 53 - 1的值。

double
64位(雙精度)浮點數(shù),由IEEE 754標準規(guī)定。
這兩個intdouble的亞型num。 num類型支持基本的運算符,如+, - ,/和*,以及abs(),ceil()floor()其他方法已在其中定義。(按位運算符,例如>>,在int類中定義。)如果num及其子類型沒有您要查找的內容,則 dart:math庫可能會定義。
整數(shù)是沒有小數(shù)點的數(shù)字。以下是定義整型字面值的一些示例:

var x = 1;
var hex = 0xDEADBEEF;

如果數(shù)字包含小數(shù),則為雙精度數(shù)。以下是定義雙精度字面值的一些示例:

var y = 1.1;
var exponents = 1.42e5;

從Dart 2.1開始,必要時整型字面值會自動轉換為雙精度數(shù):

double z = 1; // Equivalent to double z = 1.0.

版本說明: 在Dart 2.1之前,在雙精度數(shù)變量賦值為整型字面值是錯誤的。

以下是將字符串轉換為數(shù)字的方法,反之亦然:

// String -> int
var one = int.parse('1');
assert(one == 1);

// String -> double
var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);

// int -> String
String oneAsString = 1.toString();
assert(oneAsString == '1');

// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');

int類型具有傳統(tǒng)的按位移位(<<,>>),AND(&)和OR(|)運算符。例如:

assert((3 << 1) == 6); // 0011 << 1 == 0110
assert((3 >> 1) == 1); // 0011 >> 1 == 0001
assert((3 | 4) == 7); // 0011 | 0100 == 0111

字面值數(shù)字是編譯時常量。許多算術表達式也是編譯時常量,因為它們的操作數(shù)是編譯為數(shù)字的編譯時常量。

const msPerSecond = 1000;
const secondsUntilRetry = 5;
const msUntilRetry = secondsUntilRetry * msPerSecond;

Strings

Dart字符串是一系列UTF-16代碼單元。您可以使用單引號或雙引號來創(chuàng)建字符串:

var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";
var s3 = 'It\'s easy to escape the string delimiter.';
var s4 = "It's even easier to use the other delimiter.";

您可以使用表達式將表達式的值放在字符串中 。如果表達式是標識符,則可以跳過{}。要獲取與對象相對應的字符串,Dart會調用該對象的方法。${expression}toString()

var s = 'string interpolation';

assert('Dart has $s, which is very handy.' ==
    'Dart has string interpolation, ' +
        'which is very handy.');
assert('That deserves all caps. ' +
        '${s.toUpperCase()} is very handy!' ==
    'That deserves all caps. ' +
        'STRING INTERPOLATION is very handy!');

注: 在==兩個物體操作測試是否是等價的。如果兩個字符串包含相同的代碼單元序列,則它們是等效的。(這一點和java是不同的,java,String的==運算符,只有當?shù)刂芬粯樱置嬷狄粯?,才能使相等的,dart String 的== 相當于java String的equal)

您可以使用相鄰的字符串字面值或+ 運算符來連接字符串:

var s1 = 'String '
    'concatenation'
    " works even over line breaks.";
assert(s1 ==
    'String concatenation works even over '
    'line breaks.');

var s2 = 'The + operator ' + 'works, as well.';
assert(s2 == 'The + operator works, as well.');

創(chuàng)建多行字符串的另一種方法:使用帶有單引號或雙引號的三引號:

var s1 = '''
You can create
multi-line strings like this one.
''';

var s2 = """This is also a
multi-line string.""";

您可以通過為其添加前綴來創(chuàng)建“raw”字符串r:

var s = r'In a raw string, not even \n gets special treatment.';

有關如何在字符串中表示Unicode字符的詳細信息,請參閱Runes。

字符串字面值是編譯時常量,因為任何插值表達式是一個編譯時常量,其值為null或數(shù)值,字符串或布爾值。

// These work in a const string.
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';

// These do NOT work in a const string.
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1, 2, 3];

const validConstString = '$aConstNum $aConstBool $aConstString';
// const invalidConstString = '$aNum $aBool $aString $aConstList';

有關使用字符串的更多信息,請參閱 字符串和正則表達式

Booleans

為了表示布爾值,Dart具有一個名為的類型bool。只有兩個對象具有bool類型:boolean 字面值 true和false,它們都是編譯時常量。

Dart的類型安全意味著你不能使用像或 那樣的代碼,如下:

if (nonbooleanValue)
  assert (nonbooleanValue)

應該明確能計算出值:

// Check for an empty string.
var fullName = '';
assert(fullName.isEmpty);

// Check for zero.
var hitPoints = 0;
assert(hitPoints <= 0);

// Check for null.
var unicorn;
assert(unicorn == null);

// Check for NaN.
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);

Lists

也許幾乎每種編程語言中最常見的集合是數(shù)組或有序的對象組。在Dart中,數(shù)組是 List對象,因此大多數(shù)人只是將它們稱為列表。

Dart List文字看起來像JavaScript數(shù)組字面值。這是一個簡單的Dart List:

var list = [1, 2, 3];

注意: Dart推斷出list有類型List<int>。如果嘗試將非整數(shù)對象添加到此List,則分析器或運行時會引發(fā)錯誤。有關更多信息,請閱讀 類型推斷。

List使用從零開始的索引,list.length - 1是最后一個元素的索引。您可以獲得List的長度并像在JavaScript中一樣引用List元素:

var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);

list[1] = 1;
assert(list[1] == 1);

要創(chuàng)建一個編譯時常量const的List,請在List文字前添加const

var constantList = const [1, 2, 3];
// constantList[1] = 1; // Uncommenting this causes an error. 

List類型有許多方便的方法來操作List。有關List的更多信息,請參閱泛型集合

Sets

Dart中的set是一組無序的獨特item集合。對集合的Dart支持由set 字面值和Set類型提供。
這是一個簡單的Dart集,使用set 字面值創(chuàng)建:

var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};

Dart推斷出halogens具有該類型 Set<String>。如果您嘗試向集合中添加錯誤類型的值,則分析器或運行時會引發(fā)錯誤。有關更多信息,請閱讀 類型推斷。

要創(chuàng)建一個空集,請使用{}前面帶有類型參數(shù),或者指定{}給類型的變量Set:

var names = <String>{};
// Set<String> names = {}; // This works, too.
// var names = {}; // Creates a map, not a set.

Set還是Map? Map字面值的語法類似于Set字面值的語法。由于Map的優(yōu)先級靠前,因此{}默認為Map類型。如果您忘記了類型注釋{}或它所分配的變量,則Dart會創(chuàng)建一個類型的對象Map<dynamic, dynamic>。

使用add()或addAll()方法將項添加到現(xiàn)有集:

var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);

使用.length得到的一組Set的數(shù)量:

var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
assert(elements.length == 5);

要創(chuàng)建一個編譯時常量const的集合,請在set literal之前添加const

final constantSet = const {
  'fluorine',
  'chlorine',
  'bromine',
  'iodine',
  'astatine',
};
// constantSet.add('helium'); // Uncommenting this causes an error.

有關集的更多信息,請參閱 泛型Set。

Maps

通常,映射是關聯(lián)鍵和值的對象。鍵和值都可以是任何類型的對象。每個只出現(xiàn)一次,但您可以多次使用相同的。Map的Dart支持由Map字面值和Map類型提供。

這里有幾個簡單的Dart Map例子,使用Map字面值創(chuàng)建:

var gifts = {
  // Key:    Value
  'first': 'partridge',
  'second': 'turtledoves',
  'fifth': 'golden rings'
};

var nobleGases = {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};

Dart推斷出gifts的類型 Map<String, String>以及nobleGases類型的 Dart Map<int, String>。如果您嘗試將錯誤類型的值添加到任一映射,則分析器或運行時會引發(fā)錯誤。有關更多信息,請閱讀 類型推斷。

您可以使用Map構造函數(shù)創(chuàng)建相同的對象:

var gifts = Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';

var nobleGases = Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';

注意: 您可能想添加new而不僅僅是Map()。從Dart 2開始,new關鍵字是可選的。有關詳細信息,請參閱使用構造函數(shù)。

像在JavaScript中一樣,將新的鍵值對添加到現(xiàn)有Map中:

var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // Add a key-value pair

以與在JavaScript中相同的方式從Map中檢索值:

var gifts = {'first': 'partridge'};
assert(gifts['first'] == 'partridge');

如果您查找不在Map中的鍵,則會得到null作為回報:

var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null);

使用.length得到的映射中的鍵值對的數(shù)量:

var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);

要創(chuàng)建一個編譯時常量const的Map,請在Map字面值之前添加const
有關Map的更多信息,請參閱 泛型Map。

Runes

在Dart中,Runes是字符串的UTF-32表達。
Unicode為世界上所有書寫系統(tǒng)中使用的每個字母,數(shù)字和符號定義唯一的數(shù)值。由于Dart字符串是UTF-16代碼單元的序列,因此在字符串中表示32位Unicode值需要特殊語法。
表達Unicode代碼點的常用方法是 \uXXXX,XXXX是4位十六進制值。例如,心臟角色(?)是\u2665。要指定多于或少于4個十六進制數(shù)字,請將值放在大括號中。例如,笑的表情符號(??)是\u{1f600}。
字符串 類有幾個屬性,你可以用它來提取Runes信息。在codeUnitAtcodeUnit屬性返回16位編碼單元。使用該runes屬性獲取字符串的Runes。

以下示例說明了符文,16位代碼單元和32位代碼點之間的關系。

main() {
  var clapping = '\u{1f44f}';
  print(clapping);
  print(clapping.codeUnits);
  print(clapping.runes.toList());

  Runes input = new Runes(
      '\u2665  \u{1f605}  \u{1f60e}  \u{1f47b}  \u{1f596}  \u{1f44d}');
  print(new String.fromCharCodes(input));
}

注意: 使用列表操作操作符文時要小心。這種方法很容易使字符串解體,具體取決于特定的語言,字符集和操作。有關更多信息,請參閱 如何在Dart中反轉字符串?在Stack Overflow上。

Symbols

Symbol對象表示在Dart程序中聲明的運算符或標識符。您可能永遠不需要使用符號,但它們對于按名稱引用標識符的API非常有用,因為縮小會更改標識符名稱而不會更改標識符符號。要獲取標識符的符號,請使用符號文字,它只是#后跟標識符:(這一段實在不會翻譯了- -)
要獲取標識符的符號,請使用符號文字, #后面跟著標識符:

 #radix
 #bar

Symbols文字是編譯時常量。

Functions

Dart是一種真正的面向對象語言,因此即使是函數(shù)也是對象并且具有類型Function。 這意味著函數(shù)可以分配給變量或作為參數(shù)傳遞給其他函數(shù)。您也可以調用Dart類的實例,就好像它是一個函數(shù)一樣。有關詳細信息,請參閱Callable classes

以下是實現(xiàn)函數(shù)的示例:

bool isNoble(int atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}

雖然Effective Dart建議 為公共API聲明返回值類型,但如果省略類型,該函數(shù)仍然有效:

isNoble(atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}

對于只包含一個表達式的函數(shù),可以使用簡寫語法:

bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;

這個 => 是{ return expr; }的速記 . 。有時將=> 表示法稱為箭頭語法。
只有表達式(而不是語句)能夠出現(xiàn)在箭頭(=>)和分號(;)之間。例如,您不能在其中放置if語句,但可以使用條件表達式。
函數(shù)可以有兩種類型的參數(shù):必需和可選。首先列出所需參數(shù),然后列出任何可選參數(shù)。命名的可選參數(shù)也可以標記為@required。有關詳細信息,請參閱下一節(jié)。

可選參數(shù)

可選參數(shù)可以是位置參數(shù),也可以是名稱參數(shù),但不能同時包含

可選的名稱參數(shù)

調用函數(shù)時,可以使用指定名稱參數(shù) 。例如:paramName: value

enableFlags (bold :true ,hidden :false );  

定義函數(shù)時,用于 指定名稱參數(shù):{param1, param2, …}

/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold, bool hidden}) {...}

Flutter實例創(chuàng)建表達式可能變得復雜,因此窗口小部件構造函數(shù)僅使用命名參數(shù)。這使得實例創(chuàng)建表達式更易于閱讀。
您可以使用@required在任何Dart代碼(不僅僅是Flutter)中注釋命名參數(shù), 以指示它是必需參數(shù)。例如:

const Scrollbar({Key key, @required Widget child})

當一個Scrollbar構造,當必要參數(shù)缺少時,編譯器會報錯。
requaredmate包中定義??梢?code>package:meta/meta.dart直接導入 ,也可以導入另一個導出的包 meta,例如Flutter package:flutter/material.dart。

可選的位置參數(shù)

包裝一組函數(shù)參數(shù)將[]它們標記為可選的位置參數(shù):

String say(String from, String msg, [String device]) {
  var result = '$from says $msg';
  if (device != null) {
    result = '$result with a $device';
  }
  return result;
}

這是一個在沒有可選參數(shù)的情況下調用此函數(shù)的示例:

assert(say('Bob', 'Howdy') == 'Bob says Howdy');

以下是使用第三個參數(shù)調用此函數(shù)的示例:

assert(say('Bob', 'Howdy', 'smoke signal') ==
    'Bob says Howdy with a smoke signal');

默認參數(shù)值
您的函數(shù)可用于=定義命名和位置參數(shù)的默認值。默認值必須是編譯時常量。如果未提供默認值,則默認值為null。
以下是為命名參數(shù)設置默認值的示例:

/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold = false, bool hidden = false}) {...}

// bold will be true; hidden will be false.
enableFlags(bold: true);

棄用注釋: 舊代碼可能使用冒號(:)而不是= 設置命名參數(shù)的默認值。原因是最初只:支持命名參數(shù)。該支持可能已被棄用,因此我們建議您 使用=指定默認值。

下一個示例顯示如何設置位置參數(shù)的默認值:

String say(String from, String msg,
    [String device = 'carrier pigeon', String mood]) {
  var result = '$from says $msg';
  if (device != null) {
    result = '$result with a $device';
  }
  if (mood != null) {
    result = '$result (in a $mood mood)';
  }
  return result;
}

assert(say('Bob', 'Howdy') ==
    'Bob says Howdy with a carrier pigeon');

您還可以將List或Map作為默認值傳遞。以下示例定義了一個函數(shù),該函數(shù)doStuff()指定參數(shù)的默認List和list 參數(shù)的默認Map gifts。

void doStuff(
    {List<int> list = const [1, 2, 3],
    Map<String, String> gifts = const {
      'first': 'paper',
      'second': 'cotton',
      'third': 'leather'
    }}) {
  print('list:  $list');
  print('gifts: $gifts');
}

main()函數(shù)

每個應用程序都必須具有頂級main()功能,該功能用作應用程序的入口點。該main()函數(shù)返回void并具有List<String>參數(shù)的可選參數(shù)。
以下main()是Web應用程序功能的示例:

void main() {
  querySelector('#sample_text_id')
    ..text = 'Click me!'
    ..onClick.listen(reverseText);
}

注意:..前面代碼中 的語法稱為級聯(lián)。使用級聯(lián),您可以對單個對象的成員執(zhí)行多個操作。

以下main()是帶參數(shù)的命令行應用程序的函數(shù)示例:

// Run the app like this: dart args.dart 1 test
void main(List<String> arguments) {
  print(arguments);

  assert(arguments.length == 2);
  assert(int.parse(arguments[0]) == 1);
  assert(arguments[1] == 'test');
}

您可以使用args庫來定義和解析命令行參數(shù)。

Function 作為第一類對象的功能

您可以將函數(shù)作為參數(shù)傳遞給另一個函數(shù)。例如:

void printElement(int element) {
  print(element);
}

var list = [1, 2, 3];

// Pass printElement as a parameter.
list.forEach(printElement);

您還可以為變量分配函數(shù),例如:

var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');

此示例使用了匿名函數(shù)。更多關于下一節(jié)的內容。

匿名函數(shù)

大多數(shù)函數(shù)都被命名,例如main()或printElement()。您還可以創(chuàng)建一個名為匿名函數(shù)的無名函數(shù),有時也可以創(chuàng)建一個lambda或閉包。您可以為變量分配匿名函數(shù),以便例如可以在集合中添加或刪除它。

匿名函數(shù)看起來類似于命名函數(shù) - 零個或多個參數(shù),在逗號和括號之間用逗號和可選類型注釋分隔。

后面的代碼塊包含函數(shù)的主體:

([[Type] param1[, …]]) {
codeBlock;
};

以下示例使用無類型參數(shù)item定義匿名函數(shù),為List中的每個項調用的函數(shù)將打印一個包含指定索引處的值的字符串。

var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
  print('${list.indexOf(item)}: $item');
});

如果函數(shù)只包含一個語句,則可以使用箭頭表示法縮短它。

list.forEach(
    (item) => print('${list.indexOf(item)}: $item'));

作用域

Dart是有作用域的語言,這意味著變量的范圍是靜態(tài)確定的,只需通過代碼的布局。您可以“向外跟隨花括號”以查看變量是否在范圍內。
以下是每個范圍級別包含變量的嵌套函數(shù)示例:

bool topLevel = true;

void main() {
  var insideMain = true;

  void myFunction() {
    var insideFunction = true;

    void nestedFunction() {
      var insideNestedFunction = true;

      assert(topLevel);
      assert(insideMain);
      assert(insideFunction);
      assert(insideNestedFunction);
    }
  }
}

請注意如何使用nestedFunction()每個級別的變量,一直到頂級。

閉包

一個閉包是能夠訪問在其作用域的變量的函數(shù)的對象,即使當函數(shù)用于其原來的范圍之外。
函數(shù)可以關閉周圍范圍中定義的變量。在以下示例中,makeAdder()捕獲變量addBy。無論返回的函數(shù)在哪里,它都記錄addBy。

/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(num addBy) {
  return (num i) => addBy + i;
}

void main() {
  // Create a function that adds 2.
  var add2 = makeAdder(2);

  // Create a function that adds 4.
  var add4 = makeAdder(4);

  assert(add2(3) == 5);
  assert(add4(3) == 7);
}

測試函數(shù)是否相等

以下是測試頂級函數(shù),靜態(tài)方法和實例方法的相等性的示例:

void foo() {} // A top-level function

class A {
  static void bar() {} // A static method
  void baz() {} // An instance method
}

void main() {
  var x;

  // Comparing top-level functions.
  x = foo;
  assert(foo == x);

  // Comparing static methods.
  x = A.bar;
  assert(A.bar == x);

  // Comparing instance methods.
  var v = A(); // Instance #1 of A
  var w = A(); // Instance #2 of A
  var y = w;
  x = w.baz;

  // These closures refer to the same instance (#2),
  // so they're equal.
  assert(y.baz == x);

  // These closures refer to different instances,
  // so they're unequal.
  assert(v.baz != w.baz);
}

返回值

foo() {}
assert(foo() == null);

運算符

Dart定義下表中顯示的運算符。您可以覆蓋許多運算符,如在 可重寫運算符

描述 運算符
一元后綴 expr++ expr-- () [] . ?.
一元前綴 -expr !expr ~expr ++expr --expr
* / % ~/
添加 + -
位移 << >> >>>
按位與 &
按位異或 ^
按位或 |
大小和類型測試 >= > <= < as is is!
相等性 == !=
邏輯與 &&
邏輯或 ||
非空 ??
?表達式 expr1 ? expr2 : expr3
級聯(lián) ..
再運算 = *= /= += -= &= ^= etc.

警告: 運算符優(yōu)先級是Dart解析器行為。有關明確的規(guī)則,請參閱Dart語言規(guī)范中的語法

使用運算符時,可以創(chuàng)建表達式。以下是運算符表達式的一些示例:

a++
a + b
a = b
a == b
c ? a : b
a is T

運算符表中,每個運算符的優(yōu)先級高于其后的行中的運算符。例如,乘法運算符的%優(yōu)先級高于(因此之前執(zhí)行)等于運算符==,它的優(yōu)先級高于邏輯AND運算符&&。該優(yōu)先級意味著以下兩行代碼執(zhí)行相同的方式:

// Parentheses improve readability.
if ((n % i == 0) && (d % i == 0)) ...

// Harder to read, but equivalent.
if (n % i == 0 && d % i == 0) ...

警告: 對于處理兩個操作數(shù)的運算符,最左邊的操作數(shù)確定使用哪個對象的運算符。例如,如果您有Vector對象和Point對象,則aVector + aPoint使用Vector對象的+。

算術運算符

Dart支持通常的算術運算符,如下表所示。

Operator Meaning
+
-expr 負號
* 乘法
/ 除法
~/ 整除
% 獲取整數(shù)除法的余數(shù)(模數(shù))

例:

assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5); // Result is a double
assert(5 ~/ 2 == 2); // Result is an int
assert(5 % 2 == 1); // Remainder

assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');

Dart還支持前綴和后綴增量和減量運算符。

操作者 含義
++var var = var + 1(表達式值是var + 1)
var++ var = var + 1(表達式值是var)
--var var = var – 1(表達式值是var – 1)
var-- var = var – 1(表達式值是var)
var a, b;

a = 0;
b = ++a; // Increment a before b gets its value.
assert(a == b); // 1 == 1

a = 0;
b = a++; // Increment a AFTER b gets its value.
assert(a != b); // 1 != 0

a = 0;
b = --a; // Decrement a before b gets its value.
assert(a == b); // -1 == -1

a = 0;
b = a--; // Decrement a AFTER b gets its value.
assert(a != b); // -1 != 0

相等和關系運算符

下表列出了相等運算符和關系運算符的含義。

操作者 含義
== 等于; 見下面的討論
!= 不相等
> 比...更棒
< 少于
>= 大于或等于
<= 小于或等于

要測試兩個對象x和y是否表示相同的事物,請使用 ==運算符。(在極少數(shù)情況下,您需要知道兩個對象是否是完全相同的對象,請使用相同的() 函數(shù)。)以下是==運算符的工作方式:

  1. 如果xy為null,則如果兩者都為null則返回true;如果只有一個為null,則返回false。

  2. 返回方法調用的結果 。(這是正確的,運算符,例如在第一個操作數(shù)上調用的方法。您甚至可以覆蓋許多運算符,包括,正如您在Overridable運算符中看到的那樣 。)*x*.==(*y*)``==``==

這是使用每個相等和關系運算符的示例:
assert(2 == 2);
assert(2 != 3);
assert(3 > 2);
assert(2 < 3);
assert(3 >= 3);
assert(2 <= 3);

類型檢測運算符

使用as,is和is!運算符可以方便地在運行時檢查類型。

操作者 含義
as Typecast(也用于指定庫前綴)
is 如果對象具有指定的類型,則為True
is! 如果對象具有指定的類型,則返回false

obj is T如果obj實現(xiàn)了指定的接口,則結果為true T。例如,obj is Object總是如此。
使用as運算符將對象強制轉換為特定類型。通常,您應該使用它作為is對使用該對象的表達式后跟對象的測試的簡寫。例如,請考慮以下代碼:

if (emp is Person) {
  // Type check
  emp.firstName = 'Bob';
}

您可以使用as運算符縮短代碼:

(emp as Person).firstName = 'Bob';

注意: 代碼不相同。如果emp為null或不是Person,則第一個示例(with is)不執(zhí)行任何操作; 第二個(帶as)拋出一個異常。

賦值操作符

如您所見,您可以使用=運算符分配值。要僅在變量為null時分配,請使用??=運算符,如下,如果為null就執(zhí)行f

// Assign value to a
a = value;
// Assign value to b if b is null; otherwise, b stays the same
b ??= value;

復合賦值運算符,例如+=將操作與賦值組合在一起。

= –= /= %= >>= ^=
+= *= ~/= <<= &= |=

以下是復合賦值運算符的工作原理:

復合賦值 等價表達
對于運營商op: a op= b a = a op b
例: a += b a = a + b

以下示例使用賦值和復合賦值運算符:

var a = 2; // Assign using =
a *= 3; // Assign and multiply: a = a * 3
assert(a == 6);

邏輯運算符

您可以使用邏輯運算符反轉或組合布爾表達式

操作者 含義
!expr 反轉以下表達式(將false更改為true,反之亦然)
|| 邏輯或
&& 邏輯AND

以下是使用邏輯運算符的示例:

if (!done && (col == 0 || col == 3)) {
  // ...Do something...
}

按位和移位運算符

您可以在Dart中操縱數(shù)字的各個位。通常,您將使用這些按位和移位運算符和整數(shù)。

操作者 含義
&
|
^ 異或
~expr 一元逐位補碼(0s變?yōu)?s; 1s變?yōu)?s)
<< 向左位移
>> 向右位移

這是使用按位和移位運算符的示例:

final value = 0x22;
final bitmask = 0x0f;

assert((value & bitmask) == 0x02); // AND
assert((value & ~bitmask) == 0x20); // AND NOT
assert((value | bitmask) == 0x2f); // OR
assert((value ^ bitmask) == 0x2d); // XOR
assert((value << 4) == 0x220); // Shift left
assert((value >> 4) == 0x02); // Shift right

條件表達式

Dart有兩個運算符,可以讓您簡明地計算可能需要if-else語句的表達式:

condition ? expr1 : expr2

如果condition為true,則計算expr1(并返回其值); 否則,計算并返回expr2的值。

`expr1 ?? expr2`

如果expr1為非null,則返回其值; 否則,計算并返回expr2的值。
當您需要根據布爾表達式分配值時,請考慮使用?:

var visibility = isPublic ?'public' :'private' ;   

如果布爾表達式測試為null,請考慮使用??。

String playerName(String name) => name ?? 'Guest'; 

前面的例子至少可以用其他兩種方式編寫,但不夠簡潔:

// Slightly longer version uses ?: operator.
String playerName(String name) => name != null ? name : 'Guest';

// Very long version uses if-else statement.
String playerName(String name) {
  if (name != null) {
    return name;
  } else {
    return 'Guest';
  }
}

級聯(lián)符號..

(Cascades)級聯(lián)符號 .. 允許您對同一對象進行一系列操作。除了函數(shù)調用,您還可以訪問同一對象上的字段。這通常可以為您節(jié)省創(chuàng)建臨時變量的步驟,并允許您編寫更多流暢的代碼。

請考慮以下代碼:

querySelector('#confirm') // Get an object.
  ..text = 'Confirm' // Use its members.
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));

第一個方法調用,querySelector()返回一個選擇器對象。級聯(lián)表示法后面的代碼對此選擇器對象進行操作,忽略可能返回的任何后續(xù)值。
前面的例子相當于:

var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));

您也可以嵌套您的級聯(lián)。例如:

final addressBook = (AddressBookBuilder()
      ..name = 'jenny'
      ..email = 'jenny@example.com'
      ..phone = (PhoneNumberBuilder()
            ..number = '415-555-0100'
            ..label = 'home')
          .build())
    .build();

小心在返回實際對象的函數(shù)上構造級聯(lián)。例如,以下代碼失?。?/p>

var sb = StringBuffer();
sb.write('foo')
  ..write('bar'); // Error: method 'write' isn't defined for 'void'.
//返回為void的不能再構造級聯(lián)
.setTitle
.setView
.setIcon

該sb.write()調用無返回值,不能構造void的級聯(lián)。

其他運算符

在其他示例中,您會看到了大多數(shù)剩余的運算符:

操作者 名稱 含義
() 功能應用 表示函數(shù)調用
[] 列表訪問 引用列表中指定索引處的值
. 成員訪問 指表達式的屬性; 示例:從表達式中foo.bar選擇屬性barfoo
?. 有條件的成員訪問權限 比如.,但最左邊的操作數(shù)可以為null; 示例:從表達式中foo?.bar選擇屬性bar,foo除非foo為null(在這種情況下,值為foo?.barnull)

控制流程語句

您可以使用以下任一方法控制Dart代碼的流程:

  • if 和 else
  • for 循環(huán)
  • while和do- while循環(huán)
  • break 和 continue
  • switch 和 case
  • assert
    您還可以使用try-catch和影響控制流throw,如異常中所述。

If and else

Dart支持if帶有可選else語句的語句,如下一個示例所示。另見條件表達式。

if (isRaining()) {
  you.bringRainCoat();
} else if (isSnowing()) {
  you.wearJacket();
} else {
  car.putTopDown();
}
for循環(huán)

您可以使用標準for循環(huán)進行迭代。例如:

var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
  message.write('!');
}

Dart for循環(huán)內部的閉包捕獲了索引的值,避免了JavaScript中常見的陷阱。例如,考慮:

var callbacks = [];
for (var i = 0; i < 2; i++) {
  callbacks.add(() => print(i));
}
callbacks.forEach((c) => c());

如預期一樣,會輸出0然后1。相反,在js里會打印出2個2。
如果要迭代的對象是Iterable,則可以使用 forEach()方法。forEach()如果您不需要知道當前的迭代計數(shù)器,則使用是一個不錯的選擇:

candidates.forEach((candidate) => candidate.interview());

像List和Set這樣for-in的可迭代類也支持迭代的形式 :

var collection = [0, 1, 2];
for (var x in collection) {
  print(x); // 0 1 2
}
While and do-while

一個while循環(huán)在執(zhí)行循環(huán)內的邏輯之前,先計算表達式是否符合條件:

while (!isDone()) {
  doSomething();
}

一個while循環(huán)先計算表達式是否符合條件,然后執(zhí)行循環(huán)內的邏輯:

do {
  printLine();
} while (!atEndOfPage());
Break and continue

使用break停止循環(huán):

while (true) {
  if (shutDownRequested()) break;
  processIncomingRequests();
}

使用continue跳到下一個循環(huán)迭代:

for (int i = 0; i < candidates.length; i++) {
  var candidate = candidates[i];
  if (candidate.yearsExperience < 5) {
    continue;
  }
  candidate.interview();
}

如果您使用Iterable(如列表或集合),則可能會以不同的方式編寫該示例 :

candidates
    .where((c) => c.yearsExperience >= 5)
    .forEach((c) => c.interview());
Switch and case

Dart中的switch語句支持整數(shù),字符串或,使用==來比較的編譯時常量。比較對象必須都是同一個類的實例(而不是其任何子類型),并且該類不能覆蓋==。 枚舉類型switch語句也支持。

注意: Dart中的Switch語句適用于有限的情況,例如interpreters 或scanners。

每個非空case子句break通常以語句結束。其他有效的方式來結束一個非空的case條目是continue, throw或return。
default當沒有case子句匹配時,使用子句執(zhí)行代碼:

var command = 'OPEN';
switch (command) {
  case 'CLOSED':
    executeClosed();
    break;
  case 'PENDING':
    executePending();
    break;
  case 'APPROVED':
    executeApproved();
    break;
  case 'DENIED':
    executeDenied();
    break;
  case 'OPEN':
    executeOpen();
    break;
  default:
    executeUnknown();
}

以下示例省略break了case子句中的語句,從而產生錯誤(如果當前case擁有語句,不寫break的話,會報錯):

var command = 'OPEN';
switch (command) {
  case 'OPEN':
    executeOpen();
    // ERROR: Missing break

  case 'CLOSED':
    executeClosed();
    break;
}

但是,Dart確實支持空case句子,允許一種形式的落空(向下執(zhí)行):

var command = 'CLOSED';
switch (command) {
  case 'CLOSED': // Empty case falls through.
  case 'NOW_CLOSED':
    // Runs for both CLOSED and NOW_CLOSED.
    executeNowClosed();
    break;
}

如果你真的想要落空條目,你可以使用一個continue聲明和一個標簽:

var command = 'CLOSED';
switch (command) {
  case 'CLOSED':
    executeClosed();
    continue nowClosed;
  // Continues executing at the nowClosed label.

  nowClosed://這里是一個標簽,可以寫任意標識符
  case 'NOW_CLOSED':
    // Runs for both CLOSED and NOW_CLOSED.
    executeNowClosed();
    break;
}

一個case條目可以有局部變量,作用域是內部的條目的范圍。

斷言

assert如果布爾條件為false,斷言語句中斷正常執(zhí)行,以下為例:

// Make sure the variable has a non-null value.
assert(text != null);

// Make sure the value is less than 100.
assert(number < 100);

// Make sure this is an https URL.
assert(urlString.startsWith('https'));

注意: 斷言語句對生產代碼沒有影響; 他們只是為了發(fā)展。Flutter在調試模式下啟用斷言。 僅限開發(fā)的工具(如dartdevc) 通常默認支持斷言。一些工具,如dartdart2js, 通過命令行標志支持斷言:--enable-asserts

要將消息附加到斷言,請?zhí)砑右粋€字符串作為第二個參數(shù)。

assert(urlString.startsWith('https'),
    'URL ($urlString) should start with "https".');

第一個參數(shù)assert可以是任何解析為布爾值的表達式。如果表達式的值為true,則斷言成功并繼續(xù)執(zhí)行。如果為false,則斷言失敗并拋出異常( AssertionError)。

Exceptions

你的Dart代碼可以拋出和捕捉異常。異常是錯誤,表示發(fā)生了意外的事情。如果沒有捕獲到異常,引發(fā)異常的隔離會掛起,通常隔離及其程序會終止。

與Java相比,Dart的所有異常都是未經檢查的異常。方法不會聲明它們可能引發(fā)的異常,并且您不需要捕獲任何異常。

Dart提供了ExceptionError 類型,以及許多預定義的子類型。當然,您可以定義自己的例外情況。但是,Dart程序可以拋出任何非null對象 - 不僅僅是Exception和Error對象 - 作為異常。

Throw

以下是拋出或引發(fā)異常的示例:

throw FormatException('Expected at least 1 section');

你也可以拋出任意對象:

throw 'Out of llamas!';

注意:生產質量代碼通常會拋出實現(xiàn)錯誤異常的類型 。
因為拋出異常是一個表達式,所以可以在=>語句中以及允許表達式的任何其他地方拋出異常:

void distanceTo(Point other) => throw UnimplementedError();

Catch

要處理可能拋出多種類型異常的代碼,可以指定多個catch子句。與拋出對象的類型匹配的第一個catch子句處理異常。如果catch子句未指定類型,則該子句可以處理任何類型的拋出對象:

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  buyMoreLlamas();
}

正如上面的代碼所示,您可以使用oncatch或兩者兼而有之。使用on時需要指定異常類型。使用catch時,你的異常處理程序需要異常對象。

要處理可能拋出多種類型異常的代碼,可以指定多個catch子句。與拋出對象的類型匹配的第一個catch子句處理異常。如果catch子句未指定類型,則該子句可以處理任何類型的拋出對象:

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // A specific exception
  buyMoreLlamas();
} on Exception catch (e) {
  // Anything else that is an exception
  print('Unknown exception: $e');
} catch (e) {
  // No specified type, handles all
  print('Something really unknown: $e');
}

正如上面的代碼所示,您可以使用oncatch或兩者兼而有之。使用on時需要指定異常類型。使用catch時,你的異常處理程序需要異常對象。

您可以指定一個或兩個參數(shù)catch()。第一個是拋出的異常,第二個是堆棧跟蹤(StackTrace對象)。

try {
  // ···
} on Exception catch (e) {
  print('Exception details:\n $e');
} catch (e, s) {
  print('Exception details:\n $e');
  print('Stack trace:\n $s');
}

要部分處理異常,同時允許它傳播,請使用rethrow關鍵字。

void misbehave() {
  try {
    dynamic foo = true;
    print(foo++); // Runtime error
  } catch (e) {
    print('misbehave() partially handled ${e.runtimeType}.');
    rethrow; // Allow callers to see the exception.
  }
}

void main() {
  try {
    misbehave();
  } catch (e) {
    print('main() finished handling ${e.runtimeType}.');
  }
}

Finally

無論是否拋出異常,要確保某些代碼運行,請使用finally子句。如果沒有catch子句匹配該異常,則在finally子句運行后傳播異常:

try {
  breedMoreLlamas();
} finally {
  // Always clean up, even if an exception is thrown.
  cleanLlamaStalls();
}

該finally子句在任何匹配的catch子句之后運行:

try {
  breedMoreLlamas();
} catch (e) {
  print('Error: $e'); // Handle the exception first.
} finally {
  cleanLlamaStalls(); // Then clean up.
}

閱讀 dart之旅的Exception部分,了解更多相關信息 。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容