Dart語法篇之基礎語法(一)

簡述:編程

又是一段新的開始,Dart這門語言相信不少人都是經過Flutter這個框架才瞭解的,由於Flutter相比Dart更被咱們所熟知。不少人遲遲不肯嘗試Flutter緣由大多數是由於學習成本高,顯然擺在面前的是須要去從新學習一門新的語言dart,而後再去學習一個開發框架Flutter,再加上不少莫名奇妙的坑,不說多的就從Github上Flutter項目issue數來看坑是着實很多,因此不少人也就望而卻步了。固然這個問題是一個新的技術框架剛開始均可能存在的,但咱們更須要看到Flutter框架跨平臺技術思想先進性。swift

爲何要開始一系列Dart相關的文章?數組

很簡單,就是爲了更好地開發Flutter, 其實開發Flutter使用Dart的核心知識點並不須要太過於全面,有些東西根本用不到,因此該系列文章也將是有選擇性選取Dart一些經常使用技術點講解。另外一方面,讀過我文章的小夥伴就知道我是Kotlin的狂熱忠實粉, 其實語言都是相通,你能夠從Dart身上又能看到Kotlin的身影,因此我上手Dart很是快,能夠對比着學習。因此後期Dart文章我會將Dart與Kotlin做爲對比講解,因此若是你學過Kotlin那麼恭喜你,上手Dart將會很是快。安全

該系列Dart文章會講哪些內容呢?markdown

本系列文章主要會涉及如下內容: dart基本語法、變量常量和類型推導、集合、函數、面向對象的Mixins、泛型、生成器函數、Async和Await、Stream和Future、Isolate和EventLoop以及最後基本介紹下DartVM的工做原理。閉包

1、Hello Dart

這是第一個Hello Dart程序,不少程序入口都是從main函數開始,因此dart也不例外,一塊兒來看下百變的main函數app

//main標準寫法
void main() {
  print('Hello World!');//注意: Dart和Java同樣表達式以分號結尾,寫習慣Kotlin的小夥伴須要注意了, 這多是你從Kotlin轉Dart最大不適之一。
}

//dart中void類型,做爲函數返回值類型能夠省略
main() {
  print('Hello World!');  
}

//若是函數內部只有一個表達式,能夠省略大括號,使用"=>"箭頭函數; 
//而對於Kotlin則是若是隻有一個表達式,能夠省略大括號,使用"="鏈接,相似 fun main(args: Array<String>) = println('Hello World!')
void main() => print('Hello World!');

//最簡寫形式
main() => print('Hello World!');
複製代碼

2、數據類型

在dart中的一切皆是對象,包括數字、布爾值、函數等,它們和Java同樣都繼承於Object, 因此它們的默認值也就是null. 在dart主要有: 布爾類型bool、數字類型num(數字類型又分爲int,double,而且二者父類都是num)、字符串類型String、集合類型(List, Set, Map)、Runes類和Symbols類型(後兩個用的並不太多)框架

一、布爾類型(bool)

在dart中和C語言同樣都是使用bool來聲明一個布爾類型變量或常量,而在Kotlin則是使用Boolean 來聲明,可是一致的是它對應的值只有兩個true和false.編程語言

main() {
    bool isClosed = true;//注意,dart仍是和Java相似的 [類型][變量名]方式聲明,這個和Kotlin的 [變量名]:[類型]不同.
    bool isOpened = false;
}
複製代碼

二、數字類型(num、int、double)

在dart中num、int、double都是類,而後int、double都繼承num抽象類,這點和Kotlin很相似,在Kotlin中Number、Int、Double都是類,而後Int、Double都繼承於Number. 注意,可是在dart中沒有float, short, long類型ide

![](/Users/mikyou/Library/Application Support/marktext/images/2019-10-24-22-02-40-image.png)

main() {
    double pi = 3.141592653;
    int width = 200;
    int height = 300;
    print(width / height);//注意:這裏和Kotlin、Java都不同,兩個int類型相除是double類型小數,而不是整除後的整數。
    print(width ~/ height);//注意: 這纔是dart整除正確姿式
}
複製代碼

此外和Java、Kotlin同樣,dart也擁有一些數字經常使用的函數:

main() {
    print(3.141592653.toStringAsFixed(3)); //3.142 保留有效數字
    print(6.6.floor());//6向下取整
    print((-6.6).ceil()); //-6 向上取整
    print(9.9.ceil()); //10 向上取整
    print(666.6.round()); //667 四捨五入
    print((-666.6).abs()); // 666.6 取絕對值
    print(666.6.toInt()); //666 轉化成int,這中toInt、toDouble和Kotlin相似
    print(999.isEven); //false 是不是偶數
    print(999.isOdd); //true 是不是奇數
    print(666.6.toString()); //666.6 轉化成字符串
}
複製代碼

三、字符串類型(String)

在Dart中支持單引號、雙引號、三引號以及$字符串模板用法和Kotlin是如出一轍的。

main() {
    String name = 'Hello Dart!';//單引號
    String title = "'Hello Dart!'";//雙引號
    String description = """ Hello Dart! Hello Dart! Hello Dart! Hello Dart! Hello Dart! """;//三引號
    num value = 2;
    String result = "The result is $value";//單值引用
    num width = 200;
    num height = 300;
    String square = "The square is ${width * height}";//表達式的值引用
}
複製代碼

和Kotlin同樣,dart中也有不少字符串操做的方法,好比字符串拆分、子串等

main() {
  String url = "https://mrale.ph/dartvm/";

  print(url.split("://")[0]); //字符串分割split方法,相似Java和Kotlin

  print(url.substring(3, 9)); //字符串截取substring方法, 相似Java和Kotlin

  print(url.codeUnitAt(0)); //取當前索引位置字符的UTF-16碼

  print(url.startsWith("https")); //當前字符串是否以指定字符開頭, 相似Java和Kotlin

  print(url.endsWith("/")); //當前字符串是否以指定字符結尾, 相似Java和Kotlin

  print(url.toUpperCase()); //大寫, 相似Java和Kotlin

  print(url.toLowerCase()); //小寫, 相似Java和Kotlin

  print(url.indexOf("ph")); //獲取指定字符的索引位置, 相似Java和Kotlin

  print(url.contains("http")); //字符串是否包含指定字符, 相似Java和Kotlin

  print(url.trim()); //去除字符串的首尾空格, 相似Java和Kotlin

  print(url.length); //獲取字符串長度

  print(url.replaceFirst("t", "A")); //替換第一次出現t字符位置的字符

  print(url.replaceAll("m", "M")); //所有替換, 相似Java和Kotlin
}
複製代碼

四、類型檢查(is和is!)和強制類型轉換(as)

和Kotlin同樣,dart也是經過 is 關鍵字來對類型進行檢查以及使用 as 關鍵字對類型進行強制轉換,若是判斷不是某個類型dart中使用 is! , 而在Kotlin中正好相反則用 !is 表示。

main() {
    int number = 100;
    double distance = 200.5;
    num age = 18;
    print(number is num);//true
    print(distance is! int);//true
    print(age as int);//18
}
複製代碼

五、Runes和Symbols類型

在Dart中的Runes和Symbols類型使用並很少,這裏作個簡單的介紹, Runes類型是UTF-32字節單元定義的Unicode字符串,Unicode可使用數字表示字母、數字和符號,然而在dart中String是一系列的UTF-16的字節單元,因此想要表示32位的Unicode的值,就須要用到Runes類型。咱們通常使用\uxxxx這種形式來表示一個Unicode碼,xxxx 表示4個十六進制值。當十六進制數據多餘或者少於4位時,將十六進制數放入到花括號中,例如,微笑表情(😆)是\u{1f600}。而Symbols類型則用得不多,通常用於Dart中的反射,可是注意在Flutter中禁止使用反射。

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));
}
複製代碼

六、Object類型

在Dart中全部東西都是對象,都繼承於Object, 因此可使用Object能夠定義任何的變量,並且賦值後,類型也能夠更改。

main() {
    Object color = 'black';
    color = 0xff000000;//運行正常,0xff000000類型是int, int也繼承於Object 
}
複製代碼

七、dynamic類型

在Dart中還有一個和Object類型很是相似的類型那就是dynamic類型,下面講到的var聲明的變量未賦值的時候就是dynamic類型, 它能夠像Object同樣能夠改變類型。dynamic類型通常用於沒法肯定具體類型, 注意: 建議不要濫用dynamic,通常儘可能使用Object, 若是你對Flutter和Native原生通訊PlatformChannel代碼熟悉的話,你會發現裏面大量使用了dynamic, 由於可能native數據類型沒法對應dart中的數據類型,此時dart接收通常就會使用dynamic.

Object和dynamic區別在於: Object會在編譯階段檢查類型,而dynamic不會在編譯階段檢查類型。

main() {
    dynamic color = 'black';
    color = 0xff000000;//運行正常,0xff000000類型是int, int也繼承於Object
}
複製代碼

3、變量和常量

一、var關鍵字

在dart中可使用var來替代具體類型的聲明,會自動推導變量的類型,這是由於var並非直接存儲值,而是存儲值的對象引用,因此var能夠聲明任何變量。這一點和Kotlin不同,在Kotlin中聲明可變的變量都必須須要使用var關鍵字,而Kotlin的類型推導是默認行爲和var並無直接關係。注意: 在Flutter開發通常會常用var聲明變量,以便於能夠自動推導變量的類型。

main() {
  int colorValue = 0xff000000;
  var colorKey = 'black'; //var聲明變量 自動根據賦值的類型,推導爲String類型 
  // 使用var聲明集合變量 
  var colorList = ['red', 'yellow', 'blue', 'green'];
  var colorSet = {'red', 'yellow', 'blue', 'green'};
  var colorMap = {'white': 0xffffffff, 'black': 0xff000000};
}
複製代碼

可是在使用var聲明變量的時候,須要注意的是: 若是var聲明的變量開始不初始化,不只值能夠改變它的類型也是能夠被修改的,可是一旦開始初始化賦值後,它的類型就肯定了,後續不能被改變。

main() {
  var color; // 僅有聲明未賦值的時候,這裏的color的類型是dynamic,因此它的類型是能夠變的 
  color = 'red';
  print(color is String); //true 
  color = 0xffff0000;
  print(color is int); //true 

  var colorValue = 0xffff0000; //聲明時並賦值,這裏colorValue類型已經推導出爲int,而且肯定了類型 
  colorValue = 'red'; //錯誤,這裏會拋出編譯異常,String類型的值不能賦值給int類型 
  print(colorValue is int); //true
}
複製代碼

二、常量(final和const)

在dart中聲明常量可使用constfinal 兩個關鍵字,注意: 這二者的區別在於若是常量是編譯期就能初始化的就用const(有點相似Kotlin中的const val) 若是常量是運行時期初始化的就用final(有點相似Kotlin中的val)

main() {    
  const PI = 3.141592653;//const定義常量 
  final nowTime = DateTime.now();//final定義常量
}
複製代碼

4、集合(List、Set、Map)

一、集合List

在dart中的List和Kotlin仍是很大的區別,換句話說Dart整個集合類型系統的劃分都和Kotlin都不同,好比Dart中集合就沒有嚴格區分紅可變集合(Kotlin中MutableList)和不變集合(Kotlin中的List),在使用方式上你會感受它更像數組,可是它是能夠隨意對元素增刪改爲的。

  • List初始化方式

    main() {
        List<String> colorList = ['red', 'yellow', 'blue', 'green'];//直接使用[]形式初始化
        var colorList = <String> ['red', 'yellow', 'blue', 'green'];
    }
    複製代碼
  • List經常使用的函數

    main() {
        List<String> colorList = ['red', 'yellow', 'blue', 'green'];
        colorList.add('white');//和Kotlin相似經過add添加一個新的元素
        print(colorList[2]);//能夠相似Kotlin同樣,直接使用數組下標形式訪問元素
        print(colorList.length);//獲取集合的長度,這個Kotlin不同,Kotlin中使用的是size
        colorList.insert(1, 'black');//在集合指定index位置插入指定的元素
        colorList.removeAt(2);//移除集合指定的index=2的元素,第3個元素
        colorList.clear();//清除全部元素
        print(colorList.sublist(1,3));//截取子集合
        print(colorList.getRange(1, 3));//獲取集合中某個範圍元素
        print(colorList.join('<--->'));//相似Kotlin中的joinToString方法,輸出: red<--->yellow<--->blue<--->green
        print(colorList.isEmpty);
        print(colorList.contains('green'));    
    }
    複製代碼
  • List的遍歷方式

    main() {
        List<String> colorList = ['red', 'yellow', 'blue', 'green'];
        //for-i遍歷
        for(var i = 0; i < colorList.length; i++) {//可使用var或int
            print(colorList[i]);        
        }
        //forEach遍歷
        colorList.forEach((color) => print(color));//forEach的參數爲Function. =>使用了箭頭函數
        //for-in遍歷
        for(var color in colorList) {
            print(color);
        }
        //while+iterator迭代器遍歷,相似Java中的iteator
        while(colorList.iterator.moveNext()) {
            print(colorList.iterator.current);
        }
    }
    複製代碼

二、集合Set

集合Set和列表List的區別在於 集合中的元素是不能重複 的。因此添加劇復的元素時會返回false,表示添加不成功.

  • Set初始化方式

    main() {
        Set<String> colorSet= {'red', 'yellow', 'blue', 'green'};//直接使用{}形式初始化
        var colorList = <String> {'red', 'yellow', 'blue', 'green'};
    }
    複製代碼
  • 集合中的交、並、補集,在Kotlin並無直接給到計算集合交、並、補的API

    main() {
        var colorSet1 = {'red', 'yellow', 'blue', 'green'};
        var colorSet2 = {'black', 'yellow', 'blue', 'green', 'white'};
        print(colorSet1.intersection(colorSet2));//交集-->輸出: {'yellow', 'blue', 'green'}
        print(colorSet1.union(colorSet2));//並集--->輸出: {'black', 'red', 'yellow', 'blue', 'green', 'white'}
        print(colorSet1.difference(colorSet2));//補集--->輸出: {'red'}
    }
    複製代碼
  • Set的遍歷方式(和List同樣)

    main() {
        Set<String> colorSet = {'red', 'yellow', 'blue', 'green'};
        //for-i遍歷
        for (var i = 0; i < colorSet.length; i++) {
          //可使用var或int
          print(colorSet[i]);
        }
        //forEach遍歷
        colorSet.forEach((color) => print(color)); //forEach的參數爲Function. =>使用了箭頭函數
        //for-in遍歷
        for (var color in colorSet) {
          print(color);
        }
        //while+iterator迭代器遍歷,相似Java中的iteator
        while (colorSet.iterator.moveNext()) {
          print(colorSet.iterator.current);
        }
      }
    複製代碼

三、集合Map

集合Map和Kotlin相似,key-value形式存儲,而且 Map對象的中key是不能重複的

  • Map初始化方式

    main() {
        Map<String, int> colorMap = {'white': 0xffffffff, 'black':0xff000000};//使用{key:value}形式初始化
     var colorMap = <String, int>{'white': 0xffffffff, 'black':0xff000000};
    }
    複製代碼
  • Map中經常使用的函數

    main() {
        Map<String, int> colorMap = {'white': 0xffffffff, 'black':0xff000000};
        print(colorMap.containsKey('green'));//false
        print(colorMap.containsValue(0xff000000));//true
        print(colorMap.keys.toList());//['white','black']
        print(colorMap.values.toList());//[0xffffffff, 0xff000000]
        colorMap['white'] = 0xfffff000;//修改指定key的元素
        colorMap.remove('black');//移除指定key的元素
    }
    複製代碼
  • Map的遍歷方式

    main() {
        Map<String, int> colorMap = {'white': 0xffffffff, 'black':0xff000000};
        //for-each key-value
        colorMap.forEach((key, value) => print('color is $key, color value is $value'));
    }
    複製代碼
  • Map.fromIterables將List集合轉化成Map

    main() {
        List<String> colorKeys = ['white', 'black'];
        List<int> colorValues = [0xffffffff, 0xff000000];
        Map<String, int> colorMap = Map.fromIterables(colorKeys, colorValues);
    }
    複製代碼

四、集合經常使用的操做符

dart對於集合操做的也很是符合現代語言的特色,含有豐富的集合操做符API,可讓你處理結構化的數據更加簡單。

main() {
  List<String> colorList = ['red', 'yellow', 'blue', 'green'];
  //forEach箭頭函數遍歷
  colorList.forEach((color) => {print(color)});
  colorList.forEach((color) => print(color)); //箭頭函數遍歷,若是箭頭函數內部只有一個表達式能夠省略大括號

  //map函數的使用
  print(colorList.map((color) => '$color_font').join(","));

  //every函數的使用,判斷裏面的元素是否都知足條件,返回值爲true/false
  print(colorList.every((color) => color == 'red'));

  //sort函數的使用
  List<int> numbers = [0, 3, 1, 2, 7, 12, 2, 4];
  numbers.sort((num1, num2) => num1 - num2); //升序排序
  numbers.sort((num1, num2) => num2 - num1); //降序排序
  print(numbers);

  //where函數使用,至關於Kotlin中的filter操做符,返回符合條件元素的集合
  print(numbers.where((num) => num > 6));

  //firstWhere函數的使用,至關於Kotlin中的find操做符,返回符合條件的第一個元素,若是沒找到返回null
  print(numbers.firstWhere((num) => num == 5, orElse: () => -1)); //注意: 若是沒有找到,執行orElse代碼塊,可返回一個指定的默認值

  //singleWhere函數的使用,返回符合條件的第一個元素,若是沒找到返回null,可是前提是集合中只有一個符合條件的元素, 不然就會拋出異常
  print(numbers.singleWhere((num) => num == 4, orElse: () => -1)); //注意: 若是沒有找到,執行orElse代碼塊,可返回一個指定的默認值

  //take(n)、skip(n)函數的使用,take(n)表示取當前集合前n個元素, skip(n)表示跳過前n個元素,而後取剩餘全部的元素
  print(numbers.take(5).skip(2));

  //List.from函數的使用,從給定集合中建立一個新的集合,至關於clone一個集合
  print(List.from(numbers));

  //expand函數的使用, 將集合一個元素擴展成多個元素或者將多個元素組成二維數組展開成平鋪一個一位數組
  var pair = [
    [1, 2],
    [3, 4]
  ];
  print('flatten list: ${pair.expand((pair) => pair)}');

  var inputs = [1, 2, 3];
  print('duplicated list: ${inputs.expand((number) =>[ number, number, number ])}');
}
複製代碼

5、流程控制

一、for循環

main() {
    List<String> colorList = ['red', 'yellow', 'blue', 'green'];
    for (var i = 0; i < colorList.length; i++) {//能夠用var或int
        print(colorList[i]);
    }
}
複製代碼

二、while循環

main() {
    List<String> colorList = ['red', 'yellow', 'blue', 'green'];
    var index = 0;
    while (index < colorList.length) {
        print(colorList[index++]);
    }
}
複製代碼

三、do-while循環

main() {
    List<String> colorList = ['red', 'yellow', 'blue', 'green'];
    var index = 0;
    do {
        print(colorList[index++]);
    } while (index < colorList.length);
}
複製代碼

四、break和continue

main() {
    List<String> colorList = ['red', 'yellow', 'blue', 'green'];
    for (var i = 0; i < colorList.length; i++) {//能夠用var或int
        if(colorList[i] == 'yellow') {
            continue;
        }
        if(colorList[i] == 'blue') {
            break;
        }
        print(colorList[i]);
    }
}
複製代碼

五、if-else

void main() {
  var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
  for (var i = 0; i < numbers.length; i++) {
    if (numbers[i].isEven) {
      print('偶數: ${numbers[i]}');
    } else if (numbers[i].isOdd) {
      print('奇數: ${numbers[i]}');
    } else {
      print('非法數字');
    }
  }
}
複製代碼

六、三目運算符(? : )

void main() {
  var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
  for (var i = 0; i < numbers.length; i++) {
      num targetNumber = numbers[i].isEven ? numbers[i] * 2 : numbers[i] + 4;
      print(targetNumber);
  }
}
複製代碼

七、switch-case語句

Color getColor(String colorName) {
  Color currentColor = Colors.blue;
  switch (colorName) {
    case "read":
      currentColor = Colors.red;
      break;
    case "blue":
      currentColor = Colors.blue;
      break;
    case "yellow":
      currentColor = Colors.yellow;
      break;
  }
  return currentColor;
}
複製代碼

八、Assert(斷言)

在dart中若是條件表達式結果不知足條件,則可使用 assert 語句中斷代碼的執行。特別是在Flutter源碼中隨處可見都是assert斷言的使用。注意: 斷言只在檢查模式下運行有效,若是在生產模式運行,則斷言不會執行。

assert(text != null);//text爲null,就會中斷後續代碼執行
assert(urlString.startsWith('https'));
複製代碼

6、運算符

一、算術運算符

名稱 運算符 例子
+ var result = 1 + 1;
- var result = 5 - 1;
* var result = 3 * 5;
/ var result = 3 / 5; //0.6
整除 ~/ var result = 3 ~/ 5; //0
取餘 % var result = 5 % 3; //2

二、條件運算符

名稱 運算符 例子
大於 > 2 > 1
小於 < 1 < 2
等於 == 1 == 1
不等於 != 3 != 4
大於等於 >= 5 >= 4
小於等於 <= 4 <= 5

三、邏輯運算符

名稱 運算符 例子
|| 2 > 1 || 3 < 1
&& 2 > 1 && 3 < 1
!(2 > 1)

四、位運算符

名稱 運算符
位與 &
位或 |
位非 ~
異或 ^
左移 <<
右移 >>

五、三目運算符

condition ? expr1 : expr2

var isOpened = (value == 1) ? true : false;
複製代碼

六、空安全運算符

操做符 解釋
result = expr1 ?? expr2 若expr1爲null, 返回expr2的值,不然返回expr1的值
expr1 ??= expr2 若expr1爲null, 則把expr2的值賦值給expr1
result = expr1?.value 若expr1爲null, 就返回null,不然就返回expr1.value的值
  • 一、result = expr1 ?? expr2

    若是發現expr1爲null,就返回expr2的值,不然就返回expr1的值, 這個相似於Kotlin中的 result = expr1 ?: expr2

    main() {
        var choice = question.choice ?? 'A';
        //等價於
        var choice2;
        if(question.choice == null) {
            choice2 = 'A';
        } else {
            choice2 = question.choice;
        }
    }
    複製代碼
  • 二、expr1 ??= expr2 等價於 expr1 = expr1 ?? expr2 (轉化成第一種)

    main() {
        var choice ??= 'A';
        //等價於
        if(choice == null) {
            choice = 'A';
        }
    }
    複製代碼
  • 三、result = expr1?.value

    若是expr1不爲null就返回expr1.value,不然就會返回null, 相似Kotlin中的 ?. 若是expr1不爲null,就執行後者

    var choice = question?.choice;
    //等價於
    if(question == null){
        return null;
    } else {
        return question.choice;
    }
    
    question?.commit();
    //等價於
    if(question == null){
        return;//不執行commit()
    } else {
        question.commit();//執行commit方法 
    }
    複製代碼

七、級聯操做符(..)

級聯操做符是 .., 可讓你對一個對象中字段進行鏈式調用操做,相似Kotlin中的apply或run標準庫函數的使用。

question
    ..id = '10001'
    ..stem = '第一題: xxxxxx'
    ..choices = <String> ['A','B','C','D']
    ..hint = '聽音頻作題';
複製代碼

Kotlin中的run函數實現對比

question.run {
    id = '10001'
    stem = '第一題: xxxxxx'
    choices = listOf('A','B','C','D')
    hint = '聽音頻作題'    
}
複製代碼

八、運算符重載

在dart支持運算符自定義重載,使用operator關鍵字定義重載函數

class Vip {
  final int level;
  final int score;

  const Vip(this.level, this.score);

  bool operator >(Vip other) =>
      level > other.level || (level == other.level && score > other.score);

  bool operator <(Vip other) =>
      level < other.level || (level == other.level && score < other.score);

  bool operator ==(Vip other) =>
      level == other.level &&
      score == other.level; //注意: 這段代碼可能在高版本的Dart中會報錯,在低版本是OK的
  //上述代碼,在高版本Dart中,Object中已經重載了==,因此須要加上covariant關鍵字重寫這個重載函數。
  @override
  bool operator ==(covariant Vip other) =>
      (level == other.level && score == other.score);

  @override
  int get hashCode => super.hashCode; //伴隨着你還須要重寫hashCode,至於什麼緣由你們應該都知道
}


main() {
    var userVip1 = Vip(4, 3500);
    var userVip2 = Vip(4, 1200);
    if(userVip1 > userVip2) {
        print('userVip1 is super vip');
    } else if(userVip1 < userVip2) {
        print('userVip2 is super vip');
    }
}
複製代碼

7、異常

dart中的異常捕獲方法和Java,Kotlin相似,使用的也是try-catch-finally; 對特定異常的捕獲使用on關鍵字. dart中的常見異常有: NoSuchMethodError(當在一個對象上調用一個該對象沒有 實現的函數會拋出該錯誤)、ArgumentError (調用函數的參數不合法會拋出這個錯誤)

main() {
  int num = 18;
  int result = 0;
  try {
    result = num ~/ 0;
  } catch (e) {//捕獲到IntegerDivisionByZeroException
    print(e.toString());
  } finally {
    print('$result');
  }
}

//使用on關鍵字捕獲特定的異常
main() {
  int num = 18;
  int result = 0;
  try {
    result = num ~/ 0;
  } on IntegerDivisionByZeroException catch (e) {//捕獲特定異常
    print(e.toString());
  } finally {
    print('$result');
  }
}
複製代碼

8、函數

在dart中函數的地位一點都不亞於對象,支持閉包和高階函數,並且dart中的函數也會比Java要靈活的多,並且Kotlin中的一些函數特性,它也支持甚至比Kotlin支持的更全面。好比支持默認值參數、可選參數、命名參數等.

一、函數的基本用法

main() {
    print('sum is ${sum(2, 5)}');
}

num sum(num a, num b) {
    return a + b;
}
複製代碼

二、函數參數列表傳參規則

//num a, num b, num c, num d 最普通的傳參: 調用時,參數個數和參數順序必須固定
add1(num a, num b, num c, num d) {
  print(a + b + c + d);
}

//[num a, num b, num c, num d]傳參: 調用時,參數個數不固定,可是參數順序須要一一對應, 不支持命名參數
add2([num a, num b, num c, num d]) {
  print(a + b + c + d);
}

//{num a, num b, num c, num d}傳參: 調用時,參數個數不固定,參數順序也能夠不固定,支持命名參數,也叫可選參數,是dart中的一大特性,這就是爲啥Flutter代碼那麼多可選屬性,大量使用可選參數
add3({num a, num b, num c, num d}) {
  print(a + b + c + d);
}

//num a, num b, {num c, num d}傳參: 調用時,a,b參數個數固定順序固定,c,d參數個數和順序也能夠不固定
add4(num a, num b, {num c, num d}) {
  print(a + b + c + d);
}

main() {
  add1(100, 100, 100, 100); //最普通的傳參: 調用時,參數個數和參數順序必須固定
  add2(100, 100); //調用時,參數個數不固定,可是參數順序須要一一對應, 不支持命名參數(也就意味着順序不變)
  add3(
      b: 200,
      a: 200,
      c: 100,
      d: 100); //調用時,參數個數不固定,參數順序也能夠不固定,支持命名參數(也就意味着順序可變)
  add4(100, 100, d: 100, c: 100); //調用時,a,b參數個數固定順序篤定,c,d參數個數和順序也能夠不固定
}
複製代碼

三、函數默認參數和可選參數(以及與Kotlin對比)

dart中函數的默認值參數和可選參數和Kotlin中默認值參數和命名參數一致,只是寫法上不一樣而已

add3({num a, num b, num c, num d = 100}) {//d就是默認值參數,給的默認值是100
   print(a + b + c + d);
}

main() {
    add3(b: 200, a: 100, c: 800);
}
複製代碼

與Kotlin對比

fun add3(a: Int, b: Int, c: Int, d: Int = 100) {
    println(a + b + c + d)
}

fun main(args: Array<String>) {
    add3(b = 200, a = 100, c = 800)
}
複製代碼

四、函數類型與高階函數

在dart函數也是一種類型Function,能夠做爲函數參數傳遞,也能夠做爲返回值。相似Kotlin中的FunctionN系列函數

main() {
  Function square = (a) {
    return a * a;
  };

  Function square2 = (a) {
    return a * a * a;
  };

  add(3, 4, square, square2)
}

num add(num a, num b, [Function op, Function op2]) {
  //函數做爲參數傳遞
  return op(a) + op2(b);
}
複製代碼

五、函數的簡化以及箭頭函數

在dart中的若是在函數體內只有一個表達式,那麼就可使用箭頭函數來簡化代碼,這點也和Kotlin相似,只不過在Kotlin中人家叫lambda表達式,只是寫法上不同而已。

add4(num a, num b, {num c, num d}) {
  print(a + b + c + d);
}

add5(num a, num b, {num c, num d})  =>  print(a + b + c + d);
複製代碼

9、面向對象

在dart中一切皆是對象,因此面向對象在Dart中依然舉足輕重,下面就先經過一個簡單的例子認識下dart的面向對象,後續會繼續深刻。

一、類的基本定義和使用

abstract class Person {
    String name;
    int age;
    double height;
    Person(this.name, this.age, this.height);//注意,這裏寫法可能你們沒見過, 這點和Java是不同,這裏其實是一個dart的語法糖。可是這裏不如Kotlin,Kotlin是直接把this.name傳值的過程都省了。
    //與上述的等價代碼,固然這也是Java中必需要寫的代碼
    Person(String name, int age, double height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }   
    //然而Kotlin很完全只須要聲明屬性就行,下面是Kotlin實現代碼
    abstract class Person(val name: String, val age: Int, val height: Double) } class Student extends Person {//和Java同樣同時使用extends關鍵字表示繼承
    Student(String name, int age, double height, double grade): super(name, age, height);//在 Dart裏:類名(變量,變量,...) 是構造函數的寫法, :super()表示該構造調用父類,這裏構造時傳入三個參數
}
複製代碼

二、類中屬性的getter和setter訪問器(相似Kotlin)

abstract class Person {
  String _name; ////至關於kotlin中的var 修飾的變量有setter、getter訪問器,在dart中沒有訪問權限, 默認_下劃線開頭變量表示私有權限,外部文件沒法訪問
  final int _age;//至關於kotlin中的val 修飾的變量只有getter訪問器
  Person(this._name, this._age); //這是上述簡寫形式

  //使用set關鍵字 計算屬性 自定義setter訪問器
  set name(String name) => _name = name;
  //使用get關鍵字 計算屬性 自定義getter訪問器
  bool get isStudent => _age > 18;
}
複製代碼

總結

這是dart的第一篇文章,主要就是從總體上介紹了下dart的語法,固然裏面還有一些東西須要深刻,後續會繼續深刻探討。總體看下有沒有以爲Kotlin和dart語法很像,其實裏面有不少特性都是現代編程語言的特性,包括你在其餘語言中一樣能看到好比swift等。就到這裏,後面繼續聊dart和flutter...

相關文章
相關標籤/搜索