Dart語言詳解
變量-變量的聲明
區別于java,新增 var dynamic Object
var:如果沒有初始值,可以變成任何類型
dynamic:動態任意類型,編譯階段不檢查類型
Object:動態任意類型,編譯階段檢查檢查類型
區別:
唯一區別 var 如果有初始值,類型被鎖定,沒有初始化的變量自動獲取一個默認值為null,一切皆對象(此對象 非彼對象),對象的默認值為null
變量-final和const
共同點:
1.聲明的類型可省略
2.初始化后不能再賦值
3.不能和var同時使用
區別:
1.類級別常量,使用static const
2.const可使用其他const 常量的值來初始化其值
3.使用const賦值聲明,const可省略
4.可以更改非final、非const變量的值,即使曾經具有const值
5.const導致的不可變性是可傳遞的
6.相同的const常量不會在內存中重復創建
7.const需要是編譯時常量
內置類型
Numbers 數值、Strings 字符串、Booleans 布爾值、Lists 列表(數組)、Sets 集合、Maps 集合、Runes 符號字符、Symbols 標識符、int : 整數值、double : 64-bit雙精度浮點數、int和double是num的子類。
特殊講解String:
Dart 字符串是 UTF-16 編碼的字符序列,可以使用單引號或者雙引號來創建字符串,可以使用三個單引號或者雙引號創建多行字符串對象,可以使用 r 前綴創建”原始raw”字符串,可以在字符串中使用表達式: ${expression},如果表達式是一個標識符,可以省略 {},如果表達式的結果為一個對象,則 Dart 會調用對象的 toString() 函數來獲取一個字符串
內置類型-List:
Dart中可以直接打印list包括list的元素,List也是對象。java中直接打印list結果是地址值
Dart中List的下標索引和java一樣從0開始和java一樣支持泛型。
有增刪改查,支持倒序,自帶排序、洗牌,可使用+將兩個List合并
內置類型-Set:
set1.difference(set2):返回set1集合里有但set2里沒有的元素集合
set1.intersection(set2):返回set1和set2的交集
set1.union(set2):返回set1和set2的并集
set1.retainAll():set1只保留某些元素(要保留的元素要在原set中存在)
內置類型-Runes:
Main(){
? Runes runes = new Runes('\u{1f605} \u6211‘);
? var str1 = String.fromCharCodes(runes);?
? print(str1);
}
Runes用于在字符串中表示Unicode字符。
使用String.fromCharCodes顯示字符圖形。
如果非4個數值,需要把編碼值放到大括號中
函數
函數定義
1.可在函數內定義
2.定義函數時可省略類型
3.支持縮寫語法 =>
Dart中函數是Function類型的對象。
所有的函數都返回一個值。如果沒有指定返回值,則 默認把語句 return null; 作為函數的最后一個語句執行。
定義函數時可省略類型(不建議)。
對于只有一個表達式的方法,你可以選擇 使用縮寫語法=>表達式來定義。(Kotlin是用=來實現)
可在函數內部定義函數,支持嵌套。
函數-可選參數:
1.可選命名參數
2.可選位置參數
3.默認參數值
可選命名參數:使用 {param1, param2, …} 的形式來指定命名參數。
可選位置參數:把可選參數放到 [] 中,必填參數要放在可選參數前面。
可選命名參數默認值(默認值必須是編譯時常量),可以使用等號‘=’或冒號’:‘。
Dart SDK 1.21 之前只能用冒號,冒號的支持以后會移除,所以建議使用等號。
可選位置參數默認值(默認值必須是編譯時常量),只能使用等號'='。
可使用list或map作為默認值,但必須是const。
函數-匿名函數
1.可賦值給變量,通過變量調用
2.可在其他函數中直接調用或傳遞給其他函數
可以通過()調用,不推薦。
常用的List.forEach()就用的匿名函數。
test((){
print("匿名函數");
});
函數-閉包
Function makeAddFunc(int x) {
? x++;
? return (int y) => x + y;
}
main() {
? var addFunc2 = makeAddFunc(2);
? var addFunc4 = makeAddFunc(4);
? print(addFunc2(3));
? print(addFunc4(3));
}
注:方法體只包含一個語句,可以使用”=>”縮寫。
函數-函數別名
typedef Fun1(int a, int b);
typedef Fun2<T, K>(T a, K b);
int add(int a, int b) {
? print('a + b');
? return a + b;
}
定義函數模版示列:typedef fun = int add(int a, int b);
test(fun param){
fun(a,b);
}
class Demo1 {
? Demo1(int f(int a, int b), int x, int y) {
? ? var sum = f(x, y);
? ? print("sum1 = $sum");
? }
}
class Demo2 {
? Demo2(Fun1 f, int x, int y) {
? ? var sum = f(x, y);
? ? print("sum2 = $sum");
? }
}
class Demo3 {
? Demo3(Fun2<int, int> f, int x, int y) {
? ? var sum = f(x, y);
? ? print("sum3 = $sum");
? }
}
注:typedef給函數起一個別名,使用比較方便。例如定義一個方法的回調,直接使用別名定義。
沒返回值,則只要參數匹配就行了,如果定義了返回值,則返回值不一樣會報錯。
操作符:
“?.”,條件成員訪問 和 . 類似,但是左邊的操作對象不能為 null,例如 foo?.bar 如果 foo 為 null 則返回 null,否則返回 bar 成員。
“~/”,除后取整。
“as”,類型轉換。
“is”,如果對象是指定類型返回true。
“is!”,如果對象是指定類型返回false。
“??”,雙問號左邊為true返回左邊結果,否則返回右邊結果。
“..”,級聯語法。嚴格來說, 兩個點的級聯語法不是一個操作符。 只是一個 Dart 特殊語法。
“??:”,如果左邊是 null,則右邊賦值給左邊;如果不是 null,則左邊的值保持不變
流程控制語句
if else
for, forEach, for-in
while , do-while
switch case
break , continue
Dart中控制流程語句和Java類似。
List和Set等實現了Iterable接口的類支持for-in遍歷元素。
Dart 提供了 Exception 和 Error 類型, 以及一些子類型。還可以定義自己的異常類型。但是,Dart 代碼可以拋出任何非 null 對象為異常,不僅僅是實現了 Exception 或者 Error 的對象。
/ 拋出Exception 對象
// throw new FormatException(‘格式異常');
// 拋出Error 對象
// throw new OutOfMemoryError();
// 拋出任意非null對象
// throw '這是一個異常';
所有的 Dart 異常是非檢查異常。 方法不一定聲明了他們所拋出的異常, 并且你不要求捕獲任何異常。
Dart 代碼可以拋出任何非 null 對象為異常,不僅僅是實現了 Exception 或者 Error 的對象。
異常-捕獲
try {
? throw new OutOfMemoryError();
} on OutOfMemoryError {
? print('沒有內存了');
} on Error catch(e) {
? print('Unknown error: $e');
} catch (e, s) {
? print('Exception details: $e');
? print('Stack Trace: $s');
} finally {
? print('end');
}
所有的 Dart 異常是非檢查異常。 方法不一定聲明了他們所拋出的異常, 并且你不要求捕獲任何異常。
Dart 代碼可以拋出任何非 null 對象為異常,不僅僅是實現了 Exception 或者 Error 的對象。
可以使用on 或者 catch 來聲明捕獲語句,也可以 同時使用。使用 on 來指定異常類型,使用 catch 來 捕獲異常對象。
catch() 可以帶有一個或者兩個參數, 第一個參數為拋出的異常對象, 第二個為堆棧信息 (一個 StackTrace 對象)。
可以使用rethrow把捕獲的異常重新拋出。
類-構造函數:
//java中寫法
class Point {
? double x;
? double y;
? Point(int x, int y) {
? ? this.x = x;
? ? this.y = y;
? }
}
//dart建議寫法
class Point {
? num x;
? num y;
? Point(this.x, this.y);
}
類-命名構造函數:
class Point {
? num x;
? num y;
? Point(this.x, this.y);
? //命名構造函數
? Point.fromJson(Map json) {
? ? x = json['x'];
? ? y = json['y'];
? }
}
使用命名構造函數可以為一個類實現多個構造函數, 或者使用命名構造函數來更清晰的表明你的意圖。
類-重定向構造函數:
class Point {
? num x;
? num y;
? Point(this.x, this.y);
? //重定向構造函數,使用冒號調用其他構造函數
? Point.alongXAxis(num x) : this(x, 0);
}
一個重定向構造函數是沒有代碼的,在構造函數聲明后,使用 冒號調用其他構造函數。
類-初始化列表:
import 'dart:math';
class Point {
? //final變量不能被修改,必須被構造函數初始化
? final num x;
? final num y;
? final num distanceFromOrigin;
? //初始化列表
? Point(x, y)
? ? ? : x = x,
? ? ? ? y = y,
? ? ? ? distanceFromOrigin = sqrt(x * x + y * y);
}
在構造函數體執行之前可以初始化實例參數。 使用逗號分隔初始化表達式。
初始化列表非常適合用來設置 final 變量的值。
類-調用超類構造函數:
eg:class Parent {
? int x;
? int y;
? //父類命名構造函數不會傳遞?
? Parent.fromJson(x, y)
? ? ? : x = x,
? ? ? ? y = y {
? ? print('父類命名構造函數');
? }
}
class Child extends Parent {
? int x;
? int y;
? //若超類沒有默認構造函數, 需要手動調用超類其他構造函數
? Child(x, y) : super.fromJson(x, y) {
? ? //調用父類構造函數的參數無法訪問 this
? ? print('子類構造函數');
? }
? //在構造函數的初始化列表中使用super(),需要把它放到最后
? Child.fromJson(x, y)
: x = x,
? y = y,
? super.fromJson(x, y) {
? ? print('子類命名構造函數');
? }
}
超類命名構造函數不會傳遞,如果希望使用超類中定義的命名構造函數創建子類,則必須在子類中實現該構造函數。
如果超類沒有默認構造函數, 則你需要手動的調用超類的其他構造函數。
調用超類構造函數的參數無法訪問 this。
在構造函數的初始化列表中使用 super(),需要把它放到最后。
類-常量構造函數:
class Point2 {
? //定義const構造函數要確保所有實例變量都是final
? final num x;
? final num y;
? static final Point2 origin = const Point2(0, 0);
? //const關鍵字放在構造函數名稱之前,且不能有函數體
? const Point2(this.x, this.y);
}
定義const構造函數要確保所有實例變量都是final。
const關鍵字放在構造函數名稱之前。
類-工廠構造函數:
class Singleton {
? String name;
? //工廠構造函數無法訪問this,所以這里要用static
? static Singleton _cache;
? //工廠方法構造函數,關鍵字factory
? factory Singleton([String name = 'singleton']) =>
? ? ? Singleton._cache ??= Singleton._newObject(name);
? //定義一個命名構造函數用來生產實例
? Singleton._newObject(this.name);
}
注:工廠構造函數是一種構造函數,與普通構造函數不同,工廠函數不會自動生成實例,而是通過代碼來決定返回的實例對象。
如果一個構造函數并不總是返回一個新的對象,則使用 factory 來定義這個構造函數。
工廠構造函數無法訪問this。
類-Setter和Getter:
class Rectangle {
? num left;
? num top;
? num width;
? num height;
? Rectangle(this.left, this.top, this.width, this.height);
? num get right => left + width;
? set right(num value) => left = value - width;
? num get bottom => top + height;
? set bottom(num value) => top = value - height;
}
每個實例變量都隱含的具有一個 getter, 如果變量不是 final 的則還有一個 setter。
可以通過實行 getter 和 setter 來創建新的屬性, 使用 get 和 set 關鍵字定義 getter 和 setter。
getter 和 setter 的好處是,你可以開始使用實例變量,后來 你可以把實例變量用函數包裹起來,而調用你代碼的地方不需要修改。
類-抽象類:
1.abstract關鍵字修飾class
2,.繼承的方式使用
3.接口的方式使用
不能被實例化,除非定義一個工廠構造函數。
抽象類通常用來定義接口, 以及部分實現。
抽象類通常具有抽象方法,抽象方法不需要關鍵字,以分號結束即可。
接口方式使用時,需要重寫抽象類的成員變量和方法,包括私有的。
一個類可以implement一個普通類。Dart任何一個類都是接口。
一個類可以implement多個接口。
類-可調用類:
class ClassFunction {
? call(String a, String b, String c) => '$a $b $c!';
}
main() {
? var cf = new ClassFunction();
? var out = cf("dongnao","flutter","damon");
? print('$out');
? print(cf.runtimeType);
? print(out.runtimeType);
? print(cf is Function);
}
實現call()方法可以讓類像函數一樣能夠被調用。