變量
聲明變量
聲明可以有兩種方式,一種是不指定類型,即使用var關(guān)鍵字
這種發(fā)方式和kotlin一樣
var name = 'Bob';
另一種是明確指定類型(Optional types),這種和java一樣
String name = 'Bob';
因?yàn)橛蓄愋屯茖?dǎo),所以兩種實(shí)現(xiàn)效果一樣,官方推薦在函數(shù)內(nèi)的本地變量盡量使用var聲明。
在變量類型并不明確的情況下,可以使用dynamic關(guān)鍵字,這種dynamic和kotlin里的any一樣
dynamic name = 'Bob';
訪問限定符
Dart 沒有類似于 Java 那樣的 public、protected 和 private 成員訪問限定符。如果一個(gè)標(biāo)識(shí)符以下劃線 (_) 開頭則表示該標(biāo)識(shí)符在庫內(nèi)是私有的
Final 和 Const
使用過程中從來不會(huì)被修改的變量, 可以使用 final 或 const,而不是 var 或者其他類型,F(xiàn)inal 變量的值只能被設(shè)置一次; Const 變量在編譯時(shí)就已經(jīng)固定 (Const 變量 是隱式 Final 的類型) 。最高級(jí) final 變量或類變量在第一次使用時(shí)被初始化。
內(nèi)建類型
Dart 語言支持以下內(nèi)建類型:
Number
String
Boolean
List (也被稱為 Array)
Map
Set
Rune (用于在字符串中表示 Unicode 字符)
Symbol
后兩個(gè)kotlin沒有,前面幾個(gè)和kotlin一樣
String
Dart 字符串是一組 UTF-16 單元序列。 字符串通過單引號(hào)或者雙引號(hào)創(chuàng)建。
字符串可以通過 ${expression} 的方式內(nèi)嵌表達(dá)式。和kotlin一樣。
使用連續(xù)三個(gè)單引號(hào)或者三個(gè)雙引號(hào)實(shí)現(xiàn)多行字符串對象的創(chuàng)建,(和kotlin不一樣)
var s1 = '''
You can create
multi-line strings like this one.
''';
使用 r 前綴,可以創(chuàng)建 “原始 raw” 字符串:(kotlin沒有)
var s = r"In a raw string, even \n isn't special.";
List,和kotlin一樣
var list = [1, 2, 3];
Set
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
var names = {}; // 這樣會(huì)創(chuàng)建一個(gè) Map ,而不是 Set 。
Map
和json字符串一樣,
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
Rune
在 Dart 中, Rune 用來表示字符串中的 UTF-32 編碼字符。
示 Unicode 編碼的常用方法是, \uXXXX, 這里 XXXX 是一個(gè)4位的16進(jìn)制數(shù)。 例如,心形符號(hào) (?) 是 \u2665。 對于特殊的非 4 個(gè)數(shù)值的情況, 把編碼值放到大括號(hào)中即可。 例如,emoji 的笑臉 (?) 是 \u{1f600}。
下面是示例演示了 Rune 、 16-bit code units、 和 32-bit code points 之間的關(guān)系。
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));
}
Symbol
一個(gè) Symbol 對象表示 Dart 程序中聲明的運(yùn)算符或者標(biāo)識(shí)符
通過字面量 Symbol ,也就是標(biāo)識(shí)符前面添加一個(gè) # 號(hào),來獲取標(biāo)識(shí)符的 Symbol 。
#radix
#bar
函數(shù)
可選參數(shù)
可選參數(shù)可以是命名參數(shù)或者位置參數(shù),但一個(gè)參數(shù)只能選擇其中一種方式修飾。
命名可選參數(shù)
調(diào)用函數(shù)時(shí),可以使用指定命名參數(shù) paramName: value。 例如:
enableFlags(bold: true, hidden: false);
定義函數(shù)是,使用 {param1, param2, …} 來指定命名參數(shù):
/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold, bool hidden}) {...}
使用 @required 注釋表示參數(shù)是 required 性質(zhì)的命名參數(shù),required參數(shù)調(diào)用時(shí)必須要傳, 該方式可以在任何 Dart 代碼中使用(不僅僅是Flutter)。
const Scrollbar({Key key, @required Widget child})
位置可選參數(shù)
將參數(shù)放到 [] 中來標(biāo)記參數(shù)是可選的:
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
默認(rèn)參數(shù)值
在定義方法的時(shí)候,可以使用 = 來定義可選參數(shù)的默認(rèn)值。 默認(rèn)值只能是編譯時(shí)常量。 如果沒有提供默認(rèn)值,則默認(rèn)值為 null。
下面是設(shè)置可選參數(shù)默認(rèn)值示例:
/// 設(shè)置 [bold] 和 [hidden] 標(biāo)志 ...
void enableFlags({bool bold = false, bool hidden = false}) {...}
// bold 值為 true; hidden 值為 false.
enableFlags(bold: true);
函數(shù)是一等對象
一個(gè)函數(shù)可以作為另一個(gè)函數(shù)的參數(shù)。 例如:
void printElement(int element) {
print(element);
}
var list = [1, 2, 3];
// 將 printElement 函數(shù)作為參數(shù)傳遞。
list.forEach(printElement);
詞法閉包
閉包 即一個(gè)函數(shù)對象,即使函數(shù)對象的調(diào)用在它原始作用域之外, 依然能夠訪問在它詞法作用域內(nèi)的變量。
函數(shù)可以封閉定義到它作用域內(nèi)的變量。 接下來的示例中, makeAdder() 捕獲了變量 addBy。 無論在什么時(shí)候執(zhí)行返回函數(shù),函數(shù)都會(huì)使用捕獲的 addBy 變量。
/// 返回一個(gè)函數(shù),返回的函數(shù)參數(shù)與 [addBy] 相加。
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
void main() {
// 創(chuàng)建一個(gè)加 2 的函數(shù)。
var add2 = makeAdder(2);
// 創(chuàng)建一個(gè)加 4 的函數(shù)。
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
級(jí)聯(lián)運(yùn)算符 (..)(kotlin沒有)
級(jí)聯(lián)運(yùn)算符 (..) 可以實(shí)現(xiàn)對同一個(gè)對像進(jìn)行一系列的操作。 除了調(diào)用函數(shù), 還可以訪問同一對象上的字段屬性。 這通??梢怨?jié)省創(chuàng)建臨時(shí)變量的步驟, 同時(shí)編寫出更流暢的代碼。
考慮一下代碼:
querySelector('#confirm') // 獲取對象。
..text = 'Confirm' // 調(diào)用成員變量。
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
第一句調(diào)用函數(shù) querySelector() , 返回獲取到的對象。 獲取的對象依次執(zhí)行級(jí)聯(lián)運(yùn)算符后面的代碼, 代碼執(zhí)行后的返回值會(huì)被忽略。
上面的代碼等價(jià)于:
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
級(jí)聯(lián)運(yùn)算符可以嵌套,例如:
final addressBook = (AddressBookBuilder()
..name = 'jenny'
..email = 'jenny@example.com'
..phone = (PhoneNumberBuilder()
..number = '415-555-0100'
..label = 'home')
.build())
.build();
賦值運(yùn)算符??=
使用 = 為變量賦值。 使用 ??= 運(yùn)算符時(shí),只有當(dāng)被賦值的變量為 null 時(shí)才會(huì)賦值給它。
// 將值賦值給變量a
a = value;
// 如果b為空時(shí),將變量賦值給b,否則,b的值保持不變。
b ??= value;
類型判定運(yùn)算符
as, is, 和 is! 運(yùn)算符用于在運(yùn)行時(shí)處理類型檢查
異常
catch
捕獲異??梢员苊猱惓@^續(xù)傳遞(除非重新拋出( rethrow )異常)。 可以通過捕獲異常的機(jī)會(huì)來處理該異常:
try {
breedMoreLlamas();
} on OutOfLlamasException {
// 一個(gè)特殊的異常
buyMoreLlamas();
} on Exception catch (e) {
// 其他任何異常
print('Unknown exception: $e');
} catch (e) {
// 沒有指定的類型,處理所有異常
print('Something really unknown: $e');
}
捕獲語句中可以同時(shí)使用 on 和 catch ,也可以單獨(dú)分開使用。 使用 on 來指定異常類型, 使用 catch 來 捕獲異常對象。
catch() 函數(shù)可以指定1到2個(gè)參數(shù), 第一個(gè)參數(shù)為拋出的異常對象, 第二個(gè)為堆棧信息
try {
// ···
} on Exception catch (e) {
print('Exception details:\n $e');
} catch (e, s) {
print('Exception details:\n $e');
print('Stack trace:\n $s');
}
finally
不管是否拋出異常, finally 中的代碼都會(huì)被執(zhí)行。 如果 catch 沒有匹配到異常, 異常會(huì)在 finally 執(zhí)行完成后,再次被拋出:
對象
構(gòu)造函數(shù)
class Point {
num x, y;
// 在構(gòu)造函數(shù)體執(zhí)行前,
// 語法糖已經(jīng)設(shè)置了變量 x 和 y。
Point(this.x, this.y);
}
命名構(gòu)造函數(shù)
使用命名構(gòu)造函數(shù)可為一個(gè)類實(shí)現(xiàn)多個(gè)構(gòu)造函數(shù), 也可以使用命名構(gòu)造函數(shù)來更清晰的表明函數(shù)意圖
class Point {
num x, y;
Point(this.x, this.y);
// 命名構(gòu)造函數(shù)
Point.origin() {
x = 0;
y = 0;
}
}
初始化列表
除了調(diào)用超類構(gòu)造函數(shù)之外, 還可以在構(gòu)造函數(shù)體執(zhí)行之前初始化實(shí)例變量。 各參數(shù)的初始化用逗號(hào)分隔。
// 在構(gòu)造函數(shù)體執(zhí)行之前,
// 通過初始列表設(shè)置實(shí)例變量。
Point.fromJson(Map<String, num> json)
: x = json['x'],
y = json['y'] {
print('In Point.fromJson(): ($x, $y)');
}
重定向構(gòu)造函數(shù)
有時(shí)構(gòu)造函數(shù)的唯一目的是重定向到同一個(gè)類中的另一個(gè)構(gòu)造函數(shù)。 重定向構(gòu)造函數(shù)的函數(shù)體為空, 構(gòu)造函數(shù)的調(diào)用在冒號(hào) (:) 之后.
和kotlin的擴(kuò)展方法寫法類型
class Point {
num x, y;
// 類的主構(gòu)造函數(shù)。
Point(this.x, this.y);
// 指向主構(gòu)造函數(shù)
Point.alongXAxis(num x) : this(x, 0);
}
常量構(gòu)造函數(shù)
如果該類生成的對象是固定不變的, 那么就可以把這些對象定義為編譯時(shí)常量。 為此,需要定義一個(gè) const 構(gòu)造函數(shù), 并且聲明所有實(shí)例變量為 final。
class ImmutablePoint {
static final ImmutablePoint origin =
const ImmutablePoint(0, 0);
final num x, y;
const ImmutablePoint(this.x, this.y);
}
工廠構(gòu)造函數(shù)
當(dāng)執(zhí)行構(gòu)造函數(shù)并不總是創(chuàng)建這個(gè)類的一個(gè)新實(shí)例時(shí),則使用 factory 關(guān)鍵字。 例如,一個(gè)工廠構(gòu)造函數(shù)可能會(huì)返回一個(gè) cache 中的實(shí)例, 或者可能返回一個(gè)子類的實(shí)例。
以下示例演示了從緩存中返回對象的工廠構(gòu)造函數(shù)
class Logger {
final String name;
bool mute = false;
// 從命名的 _ 可以知,
// _cache 是私有屬性。
static final Map<String, Logger> _cache =
<String, Logger>{};
factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
為類添加功能: Mixin
Mixin 是復(fù)用類代碼的一種途徑, 復(fù)用的類可以在不同層級(jí),之間可以不存在繼承關(guān)系。
通過 with 后面跟一個(gè)或多個(gè)混入的名稱,來 使用 Mixin , 下面的示例演示了兩個(gè)使用 Mixin 的類
class Musician extends Performer with Musical {
// ···
}
class Maestro extends Person
with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
過創(chuàng)建一個(gè)繼承自 Object 且沒有構(gòu)造函數(shù)的類,來 實(shí)現(xiàn) 一個(gè) Mixin 。 如果 Mixin 不希望作為常規(guī)類被使用,使用關(guān)鍵字 mixin 替換 class
mixin Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;
void entertainMe() {}