Flutter:Dart基礎語法入門

工作上的需要,被迫上線學習Flutter,看了下文檔和線上的專欄,人老了,怕容易忘記,記錄下筆記,如果有錯誤的地方,煩請糾正。

一、Dart簡介

Dart是Google在2011年10月正式發佈的編程語言,起初的定位是運行在瀏覽器的腳本語言。是Google大神由於不滿JavaScript開發的程序後期難維護問題,而新研發的一種面向對象編程語言。然而nodejs的出現,JavaScript很快覆蓋了全棧,很多手機應用和桌面應用也成爲了JavaScript的宿主容器。這使Dart始終不溫不火,這麼多年來內置Dart VM的瀏覽器廠家也只有Google自己的產品Chrome(現在好像已經移除)。

很多人都有疑問,爲什麼JavaScript那麼火,而Dart的開發者那麼稀缺,Flutter會選擇Dart作爲基礎語言去研發呢?這不會提高開發者的介入成本,不利於推廣嗎?個人感覺應該以下幾個原因:

  • Dart是Google自主研發產品,可以避免很多類似Oracle和Android的爭議問題。
  • 自主研發語言,可以靈活迭代,爲Flutter架構的形成做最有力的支撐。
  • Dart 尋求轉型,想彎道超車進入移動開發的領域

那麼Google選擇了用Dart語言開發Flutter框架,除了我們分析的客觀原因外,Dart本身有哪些特性是值得Flutter去選擇的?

二、Dart特性

  • Dart是聲明式佈局語言,易於閱讀和可視化,可以不通過可視化構建器,通過熱重載直接真機調試。
  • 同時支持JIT(即時編譯,JavaScript,Python)和AOT(運行前編譯,C,C++)
    Dart在開發階段,使用了JIT編譯,這可以提高它的研發效率,降低研發週期。Flutter最受歡迎的熱重載,正是因爲這一特性。而發佈的時候使用AOT,就不用像RN那樣,在JavaScript和原生中建立低效的方法調用映射,因此,Dart具有運行速度快,執行性能好的特點。
  • Drat是單線程模型,不需要像多線程那樣處理資源共享和數據同步問題,這也就意味着一個函數執行,就將執行到函數結束爲止,期間不會被其他Dart代碼所打斷。Dart的Isolate(隔離區)不會共享內存,幾個單獨的worker之間,通過事件循環在事件隊列中進行通信(類似Node)。

三、Dart基礎語法

Dart的運行依賴於Dart VM,大家可以通過安裝Dart SDK,來體驗Dart。安裝過程以MacOS爲例子,可以通過brew安裝

brew tap dart-lang/dart
brew install dart

接着在VSCode安裝Dart插件和code runner插件即可在vscode中體驗Dart編程。

跟很多編程語言一樣,Dart同樣以main函數作爲執行入口

void main() {
  print('hello world');
}

Dart變量

Dart可以通過var關鍵字創建變量,當使用var時,類型是通過編譯器推斷決定.

var name = 'tony';
print(name is String); // true

在默認情況下,未初始化的變量值爲null,所以我們不需要擔心無法判斷一個傳遞過來的變量是undefined還是null(JavaScript的表示淚目),所以不需要各種if else。

var name;
print(name); // null

Dart類型

Dart是類型安全的語言,一切皆爲對象的設計思路,任何類型都是對象類型,都繼承了頂層的Object。類如bool,int,null,函數,都是繼承於Object。

String name;
print(name is Object); // true
bool isPig;
print(isPig is Object); // true
int num;
print(num is Object); //true
void fun() {}
print(fun is Object); //true
  • 布爾類型

    在Dart中,使用bool關鍵字來定義布爾類型,而布爾類型只有兩個值,true和false,它們都是編譯時常量。

    var c1 = true;
    var c2 = false;
    print(c1 is bool); // true
    print(c2 is bool); // true
    
  • 數值類型

    在Dart中,使用num關鍵字來定義數值類型,num有兩個子類,分別爲int代表整數類型和double代表浮點類型

    num n = 10;
    print(n is int); // true
    num m = 1.1;
    print(m is double); // true
    

    除了常見的基本運算符,比如 +、-、*、/,以及位運算符外,你還能使用繼承自 num 的 abs()、round() 等方法,來實現求絕對值、取整的功能。你會發現,這些常見的運算符都繼承於num

  • 字符串類型

    在Dart中,String 由 UTF-16 的字符串組成。你可以使用${}內嵌表達式在字符串中,如果是一個表示符,可以省略{}

    var name = 'chong';
    print('my name is $name'); // my name is chong
    print('toUpperCase: ${name.toUpperCase()}'); //toUpperCase: CHONG
    

    字符串的拼接,與JavaScript一樣,Dart用“+”運算符來拼接。

    var x1 = 'chong';
    var x2 = '...';
    print(x1 + x2); // chong...
    

    對與多行字符串的拼接,Dart提供了類似JavaScript的模版字符串功能。用三個單引號或者三個雙引號聲明

    var str = '''
        my
        name
        is
        chong
      ''';
      print(str); 
      /*
        my
        name
        is
        chong
      */
    
  • 集合類型

    在Dart中,集合類型包含了數組類型和字典類型,分別對應List和Map,聲明和使用,都跟Javascript差不多

      var name = ['zhangsan', 'lisi'];
      name.add('wangwu');
      name.forEach((f) => print('$f')); // zhangsan lisi wangwu
    
      var map = {"name": 'chong', "sex": 'boy'};
      map['n'] = 'hello';
      map.forEach((k, v) => print('$k: $v')); // name: chong sex: boy n: hello
    

    在定義name時,編譯器會推斷該List爲List,所以如果add的是個int或者其他類型,會類型錯誤。同理 map 會被推斷成Map<String, String>,當然,也可以從定義的時候設定類型,而避免推斷錯誤。

      var map = <String, String>{"name": 'chong', "sex": 'boy'};
      map['n'] = 'hello';
      map.forEach((k, v) => print('$k: $v')); // name: chong sex: boy n: hello
    

Dart常量

Dart中定義常量的關鍵字有兩個,const和final,const的使用方法跟JavaScript的一樣。const和final的區別主要是const是在編譯時期已經確定的值,而final可以定義運行時的值,一旦運行結束,即不可改變。

```
  var x = 10;
  var y = 2;
  final z = x / y; 
  print(z); // 5.0
  const h = x / y; 
  print(h); // Error
```

Dart運算符

Dart的大多數運算符與其他編程語言的類似。有幾個比較特殊的運算符,用來簡化處理null的情況

  • ??運算符,x??y,表示x爲空時,取y的值,x非空時,取x的值

      var x;
      var y = 10;
      var z = x ?? y;
      print(z); // 10
    
  • ?.運算符,x?.y 如果x爲null,跳過該語句,避免報錯

      var x;
      print(x?.y); // null
    
  • ??=運算符, x??=y,如果x爲null,把y賦值給x。如果x不爲null,跳過。

      var x = 10;
      var y = 20;
      x ??= y;
      print(x); // 10
    
      var x;
      var y = 20;
      x ??= y;
      print(x); // 20
    

在Dart中,一切皆對象,所以運算符也是對象成員函數中的一部分。當你在某些應用場景需要複寫運算符時,Dart也提供了複寫機制,只要通過 operator 關鍵字複寫即可.

class Demo {
  var x, y;
  Demo(this.x, this.y);
  Demo operator +(Demo z) => Demo(x + z.x, y + z.y);
  bool operator ==(Demo v) => v.x == x && v.y == y;
}

var x = Demo(3, 3);
var y = Demo(2, 2);
var z = Demo(1, 1);
print(x == (y + z)); // true

四、函數

Dart的函數由返回值、函數名、參數、函數體4部分組成,函數也是對象,它的類型爲Function,這也意味着函數可以被定義爲變量和作爲函數參數。

  bool isCheck(int x, int y) {
    return x == y;
  }

  void printBool(Function check) {
    print('${check(1, 1)}');
  }

  printBool(isCheck); // true

Dart函數也支持箭頭表達式,使用方法跟Javascript一致。如上面的例子可以簡化爲

  bool isCheck(int x, int y) => x == y;

  void printBool(Function check) => print('${check(1, 1)}');

  printBool(isCheck); // true

作爲集大多數語言優點爲一身的編程語言,Dart設計非常靈活的函數傳參設計。設計了通過{}指定傳參,設置了通過[]設置可選參數。這也使Dart的代碼更加簡潔優雅。不會像JavaScript一樣,如果函數需要三個參數,前兩個爲空時,必須佔位。下面通過一個例子來記錄一下Dart函數的傳參。

  void demo1({int x, int y}) => print('$x,$y');
  demo1(y: 2); // null,2

  void demo2(int x, [int y]) => print('$x,$y');
  demo2(1); // 1,null
  demo2(1, 2); // 1,2

  void demo3(int x, int y) => print('$x,$y');
  demo3(1, 2); // 1,2
  demo3(1); // Error

  void demo4(int x, {int y}) => print('$x,$y');
  demo4(1); // 1,null
  demo4(1, y: 2); // 1,2
  demo4(y: 2); // Error

五、類

對象是類的實例,在Dart裏,所有對象都繼承了頂層的Object,Dart中的類定義,實例話,方法引用,跟JavaScript ES6差不多。差別點是Dart中通過 “_” 來表示私有,聲明變量和方法時,在前面加上下劃線,表示爲private,沒加的,表示爲public。

class Cat {
  var color, tail; // 顏色、尾巴
  Cat(this.color, this.tail);

  printInfo() {
    print('這是一隻${color}毛髮, ${tail}尾巴的貓🐱');
  }
}

var cat = new Cat('藍色', '長');
cat.printInfo(); // 這是一隻藍色毛髮, 長尾巴的貓🐱
  • 構造函數

    Dart中,類的構造函數有同名構造函數和命名構造函數兩種,同名構造函數,如上面代碼所示,與類同名。而命名構造函數,用以下方式定義

    class Cat {
      var color, tail; // 顏色、尾巴
      Cat(this.color, this.tail);
      Cat.defaut(var color) : this(color, '短'); // 重定向構造函數,用":"符號調用
    
      printInfo() {
        print('這是一隻${color}毛髮, ${tail}尾巴的貓🐱');
      }
    }
    
    var cat2 = Cat.defaut('白色');
    cat2.printInfo(); // 這是一隻白色毛髮, 短尾巴的貓🐱
    
  • 複用

    在面向對象編程語言中,複用是個很重要的概念,很多編程語言都有繼承承,接口等概念,來實現代碼的複用。Dart也不例外,Dart中,也引入了繼承,接口的概念。

    class Animal {
      var color, tail;
      Animal(this.color, this.tail);
    
      printInfo() {
        print('這是一隻${color}毛髮, ${tail}尾巴的貓🐱');
      }
    }
    
    class Cat extends Animal {
      var type = '大型';
      Cat(color, tail, {type}) : super(color, tail);
      @override
      printInfo() {
        print('這是一隻${color}毛髮, ${tail}尾巴的貓🐱,屬於${type}貓科');
      }
    }
    
    class Dog implements Animal {
      @override
      var color, tail;
      @override
      printInfo() {
        print('這是一隻小狗');
      }
    }
    
    var cat = new Cat("黑色", "長")..printInfo(); // 這是一隻黑色毛髮, 長尾巴的貓🐱,屬於大型貓科
    var dog = new Dog()..printInfo(); // 這是一隻小狗
    

    除了繼承和接口實現複用外,Dart還提供了Mixins方式。Mixins的中文意思是混入,就是在類中混入其他功能。在Dart中可以使用mixins實現類似多繼承的功能。

    class Poultry {
      printInfo() {
        print('這是一種家畜');
      }
    }
    
    class Big with Poultry {}
    
    var big = new Big().printInfo(); // 這是一種家畜
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章