Dart基礎
變量
變量是一個引用,未初始化的變量值是null。
Object name1 = 'Wuc';
var name2 = 'Wuc';
dynamic name3 = 'Wuc';
print('$name1 $name2 $name3');
//變量是一個引用,上面的name1、name2與name3的變量都引用了 一個內容為 “Wuc” 的 String 對象。
可以用 Object、var 與 dynamic 聲明的變量賦任何類型的值,但是背后的原理卻是非常不同。
1、Object: 與Java一樣 Object 是所有類的基類,Object 聲明的變量可以是任意類型。(在 Dart 中甚至連數字、方法和 null
都是對象,比如int。)
Object a = 1;
a = "a";
2、var: 聲明的變量在賦值的那一刻,決定了它是什么類型。
//a已經確定為num,不能再賦值字符串,編譯錯誤
var a = 1;
a = "a";
//正確
var b;
b = 1;
b = "a";
3、dynamic: 不是在編譯時候確定實際類型的, 而是在運行時。dynamic聲明的變量行為與Object一樣,使用一樣,關鍵在于運行時原理不同。
沒有初始化的變量自動獲取一個默認值為
null
(類型為數字的變量如果沒有初始化其值也是 null)。在聲明變量的時候,也可以選擇加上具體 類型:int a = 1;
對于局部變量,按照Dart代碼風格推薦,使用
var
而不是具體的類型來定義局部變量。
final 與 const
如果不打算改變一個變量,可以使用 final 和 const,它們可以替代任何類型,只能在聲明時初始化,且不能改變。
const a = 1; final b =1; final int c = 1; const int d = 1;
final 與 const 從使用上根本看不出區別,但是 final 是運行時常量,而 const是編譯器常量,它的值在編譯期就可以確定,編譯時常量能夠讓代碼運行的更高效。
//正確,已經確定的值
const a = 1;
const b = a + 1;
//錯誤,final不能在編譯時確定值,因此const也不能確定值
final a = 1;
const c = a + 1;
類的變量可以為
final
但是不能是const
。如果 const 變量在類中,需要定義為static const
靜態常量
內置的類型
與Java的八大內置基本數據類型不同,Dart 內置支持下面這些類型:
- numbers
- strings
- booleans
- lists (也被稱之為 arrays)
- maps
- runes (用于在字符串中表示 Unicode 字符)
- symbols
Numbers(數值)
num
是數字類型的父類,有兩個子類int
和 double
。
///數字類型
_numType() {
num num1 = -1.0; //是數字類型的父類,有兩個子類 int 和 double。
num num2 = 2;
int int1 = 3; //只能是整數
double d1 = 1.68; //雙精度)浮點數
print("num:$num1 num:$num2 int:$int1 double:$d1");
print(num1.abs()); //求絕對值
print(num1.toInt()); //轉換成int
print(num1.toDouble()); //轉換成Double
}
Strings(字符串)
Dart 字符串是 UTF-16 編碼的字符序列。 可以使用單引號或者雙引號來創建字符串,單引號和雙引號可以嵌套使用,否則需要使用`\`進行轉義。字符串中也可以引用變量與表達式。
var name = 'wuc';
//如果插入一個簡單的標識符,而后面沒有緊跟更多的字母數字文本,那么{}應該被省略。
var a = "my name is $name!";
var b = "my name is ${name.toUpperCase()}!";
與Java一樣可以使用 `+` 操作符來把拼接字符串,也可以把多個 字符串放到一起來實現同樣的功能:
var a = "my name is " "lance";
使用三個單引號或者雙引號可以 創建多行字符串對象
var s1 = '''
You can create
multi-line strings like this one.
''';
var s2 = """This is also a
multi-line string.""";
提供一個 `r` 前綴可以創建一個 “原始 raw” 字符串
print(r"換行符:\n"); // 換行符:\n r:不需要轉義
print("換行符:\\n"); // 換行符:\n
///字符串
_stringType() {
String str1 = '字符串', str2 = "雙引號"; //字符串定義
String str3 = 'st1:$str1 str2:$str2'; //字符串拼接
String str5 = '常用數據類型,請看控制臺輸出';
String str4 = 'st1:' + str1 + ' str2:' + str2; //字符串拼接
print(str3);
print(str4);
//常用方法
print(str5.substring(1, 5)); //字符串截取
print(str5.indexOf('類型')); //獲取指定字符串位置
}
Booleans(布爾值)
Dart 有一個名字為 `bool` 的類型。 只有兩個對象是布爾類型的:`true` 和 `false` 。這一點和Java沒有太大的區別。
///布爾類型,Dart 是強 bool 類型檢查,只有bool 類型的值是true 才被認為是true
_boolType() {
bool success = true, fail = false;
print(success);
print(fail);
print(success || fail); //true
print(success && fail); //false
}
Lists(列表)
幾乎所有編程語言中最常見的集合可能是數組或有序對象組。在Dart中,數組就是`List`對象。對`List`進行遍歷也和Java一樣。
var list = [1, 2, 3];
//Lists 的下標索引從 0 開始,第一個元素的索引是 0. list.length - 1 是最后一個元素的索引
print(list[list.length-1]);
//修改元素
list[0] = 2;
//使用new(實際上new可以省去)
var list = new List(1);
list[0] = 2;
//在 list 字面量之前添加 const 關鍵字,可以 定義一個不變的 list 對象(編譯時常量)
var list = const [1,2,3];
i.add(2); ///錯誤,list不可變
///List集合
_listType() {
print('----_listType----');
///集合初始化的方式
List list = [1, 2, 3, '集合']; //初始化時,添加元素
print(list);
List<int> list2 = [];
// list2 = list;//錯誤做法,類型轉換錯誤
List list3 = [];
list3.add('list3'); //通過add方法添加元素
list3.addAll(list);
print(list3);
List list4 = List.generate(3, (index) => index * 2);
print(list4);
///遍歷集合的方式
for (int i = 0; i < list.length; i++) {
print(list[i]);
}
for (var o in list) {
print(o);
}
list.forEach((val) {
print(val);
});
}
Maps(映射集合)
Map:鍵值對相關的對象。 鍵和值可以是任何類型的對象。每個鍵只出現一次, 而一個值則可以出現多次。
//直接聲明,用{}表示,里面寫key和value,每組鍵值對中間用逗號隔開
var companys = {'a': '阿里巴巴', 't': '騰訊', 'b': '百度'};
var companys2 = new Map();
companys2['a'] = '阿里巴巴';
companys2['t'] = '騰訊';
companys2['b'] = '百度';
//添加元素
companys['j'] = '京東';
//獲取與修改元素
var c = companys['c']; ///沒有對應的key返回null
companys['a'] = 'alibaba';
///map是將key和value相關聯的對象,key和value都可以是任何類型的對象,并且key是唯一的如果key重復后面添加的key會替換前面的
_mapType() {
print('----_mapType----');
///Map初始化
Map names = {'xiaoming': '小明', 'xiaohong': '小紅'};
print(names);
Map ages = {};
ages['xiaoming'] = 16;
ages['xiaohong'] = 18;
print(ages);
///Map遍歷
ages.forEach((k, v) {
print('$k $v');
});
Map ages2 = ages.map((k, v) {
//迭代生成一個新Map
return MapEntry(v, k);
});
print(ages2);
for (var key in ages.keys) {
print('$key ${ages[key]}');
}
}
與List一樣,在 map字面量之前添加 `const` 關鍵字,可以 定義一個 編譯時常量 的 map
Runes(用于在字符串中表示Unicode字符)
如果需要獲得特殊字符的 Unicode 編碼,或者需要將32位的 Unicode 編碼轉換為字符串,就可以借助 Runes 類。
Dart 表達 Unicode 代碼點的常用方法是 \uXXXX,其中XXXX是4位十六進制值。要指定多于或少于4個十六進制數字,需要將值放在大括號中。
var clapping = '\u{1f44f}'; ///5個16進制 需要使用{}
print(clapping);//??
//獲得 16位代碼單元
print(clapping.codeUnits); //[55357, 56399]
//獲得unicode代碼
print(clapping.runes.toList()); //[128079]
//fromCharCode 根據字符碼創建字符串
print( String.fromCharCode(128079));
print( String.fromCharCodes(clapping.runes));
print( String.fromCharCodes([55357, 56399]));
print( String.fromCharCode(0x1f44f));
Runes input = new Runes(
'\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}');
print(String.fromCharCodes(input));
實際上在Flutter開發中Runes與下一個Symbols可能永遠也不會用到。
Symbols
操作符標識符,可以看作C中的宏。表示編譯時的一個常量
var i = #A; //常量
main() {
print(i);
switch(i){
case #A:
print("A");
break;
case #B:
print("B");
break;
}
var b = new Symbol("b");
print(#b == b); ///true
}
操作符
常見的操作符就沒什么可說的了,主要來看看Java所沒有的。
類型判定操作符
as
、 is
、 和 is!
操作符是在運行時判定對象 類型的操作符
操作符 | 解釋 |
---|---|
as |
類型轉換 |
is |
如果對象是指定的類型返回 True |
is! |
如果對象是指定的類型返回 False |
as
操作符把對象轉換為特定的類型,但是如果無法完成轉換則會拋出一個異常
is
和Java中的 instanceof
相同
賦值操作符
=
、+=
、\=
、*=
這些不必多說,還有一個 ??=
操作符用來指定 值為 null 的變量的值
b ??= value; // 如果 b 是 null,則 value 賦值給 b;
// 如果不是 null,則 b 的值保持不變
條件表達式
Dart 有兩個特殊的操作符可以用來替代 if-else 語句:
-
condition ? expr1 : expr2
如果 condition 是 true,執行 expr1 (并返回執行的結果); 否則執行 expr2 并返回其結果。
-
expr1 ?? expr2
如果 expr1 不為null,返回其值; 否則執行 expr2 并返回其結果。
級聯操作符
級聯操作符 (`..`) 可以在同一個對象上連續調用多個函數以及訪問成員變量。 使用級聯操作符可以避免創建 臨時變量, 并且寫出來的代碼看起來更加流暢:
//StringBuffer write就是Java的append
var sb = new StringBuffer();
sb..write('foo')..write('bar');
安全操作符
Dart提供了 `?.`操作符。左邊的操作對象 如果為 null 則返回 null
String sb;
//空指針
print(sb.length);
print(sb?.length);
方法
int add(int i,int j) {
return i + j;
}
//也可以選擇忽略類型(不推薦)
add( i, j) {
return i + j;
}
//對于只有一個表達式的方法,可以選擇使用縮寫語法來定義:
add(i, j) => i + j;
//在箭頭 (=>) 和分號 (;) 之間只能使用一個 表達式
一等方法對象
Dart 是一個真正的面向對象語言,方法也是對象并且具有一種類型 `Function`。 這意味著,方法可以賦值給變量,也可以當做其他方法的參數。可以把方法當做參數調用另外一個方法
var list = [1,2,3];
//將 print 方法 作為參數傳遞給forEach
list.forEach(print);
//可以將方法賦值給一個變量 類型為Funcation
var p = print;
list.forEach(p);
在Java中如果需要能夠通知調用者或者其他地方方法執行過程的各種情況,可能需要指定一個接口,比如View的onClickListener。而在Dart中,我們可以直接指定一個回調方法給調用的方法,由調用的方法在合適的時機執行這個回調。
void setListener(Function listener){
listener("Success");
}
//或者
void setListener(void listener(String result)){
listener("Success");
}
//兩種方式,第一種調用者根本不確定 回調函數的返回值、參數是些什么
//第二中則需要寫這么一大段 太麻煩了。
//第三種:類型定義 將返回值為voide,參數為一個String的方法定義為一個類型。
typedef void Listener(String result);
void setListener(Listener listener){
listener("Success");
}
方法可以有兩種類型的參數:必需的和可選的。 必需的參數需要在參數列表前面, 后面再定義可選參數。
可選命名參數
把方法的參數放到 `{}` 中就變成可選 命名參數
int add({int i, int j}) {
if(i == null || j == null){
return 0;
}
return i + j;
}
調用方法的時候,可以使用這種形式 `paramName: value` 來指定命名參數。例如:
//無必須參數
add()
//選擇傳遞參數
add(i:1)
//位置無關
add(i:1, j:2)
add(j:1, i:2)
可選位置參數
把方法的參數放到 `[]` 中就變成可選 位置參數,傳值時按照參數位置順序傳遞
int add([int i, int j]) {
if(i == null || j == null){
return 0;
}
return i + j;
}
// 1賦值給i
add(1);
// 按照順序賦值
add(1,2);
默認參數值
在定義方法的時候,可選參數可以使用 `=` 來定義可選參數的默認值。
int add([int i = 1, int j = 2]) => i + j;
int add({int i = 1, int j = 2}) => i + j;
匿名方法
沒有名字的方法,稱之為匿名方法,也可以稱之為 lambda 或者 closure 閉包。匿名方法的聲明為:
([Type] param1, …) {
codeBlock;
};
如:
var list = ['apples', 'oranges', 'grapes', 'bananas', 'plums'];
list.forEach((i) {
print(list[i]);
});
異常
和 Java 不同的是,所有的 Dart 異常是非檢查異常。 方法不一定聲明了他們所拋出的異常, 并且不要求你捕獲任何異常。
Dart 提供了 `Exception`和`Error` 類型, 以及一些子類型。你還 可以定義自己的異常類型。但是, Dart 代碼可以 拋出任何非 null 對象為異常,不僅僅是實現了 `Exception` 或者` Error` 的對象。
throw new Exception('這是一個異常');
throw '這是一個異常';
throw 123;
與Java不同之處在于捕獲異常部分,Dart中捕獲異常同樣是使用`catch`語句,但是Dart中的`catch`無法指定異常類型。需要結合`on`來使用,基本語法如下:
try {
throw 123;
} on int catch(e){
//使用 on 指定捕獲int類型的異常對象
} catch(e,s){
//函數 catch() 可以帶有一個或者兩個參數, 第一個參數為拋出的異常對象, 第二個為堆棧信息 ( StackTrace 對象)
rethrow; //使用 `rethrow` 關鍵字可以 把捕獲的異常給 重新拋出
} finally{
}