Dart 操作符、方法與異常

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是數字類型的父類,有兩個子類intdouble

 ///數字類型
  _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所沒有的。

類型判定操作符

asis、 和 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{
    
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容