Dart 語言極簡入門

wangcj123發表於2020-04-13

一、var 變數、final,const常量

  1. 變數var

變數用關鍵詞var來定義,Dart語言是型別推斷的所以在定義變數的時候可以不用指明變數的型別,例子如下

    void main() {
      var name = "小明";
      var age = 10;
      var job;

     print(name);
     print(age);
     print(job);
   }
複製程式碼

在上面例子中,定義了變數 name 和 age ,job,其中給name賦值 "小明",根據型別推斷name就是String 型別的,給 age賦值 10,根據型別推斷age 就是 int 型別的。對job沒有賦值job變數的預設值就是null。

需要注意的是變數的型別一旦確定就不能再給他賦不同型別的值。

  1. 常量final,const

常量用 final 或 const 關鍵字,例子如下

    void main() {
      final a = "好";
      const b = 1;
    }
複製程式碼

需要注意的是,常量在定義的時候一定要進行賦值,且定義好以後不能被修改否則會報錯。

二、Dart中的資料型別

在Dart中all is Object ,Dart 中有 numbers(數值型別),strings (字串型別),booleans(布林型別),lists(列表型別),maps(字典型別)等

  1. 數值型別

在Dart中數值型別只有int 和 double兩種,例子如下

   void main() {
        int a = 1;
        double b = 2;

        print(a);
        print(b);
   }
複製程式碼

上面的例子中定義了整數型別的a,和double 型別的 b,列印結果是

flutter: 1

flutter: 2.0

2.String字串型別

Dart中字串用單引號 '' 或雙引號 "" 來建立,例子如下:

  void main() {
    var a = "熱愛程式設計";
    var b = '哈哈哈哈';
    print(a);
    print(b);
  }
  
  //輸出結果:
  //flutter: 熱愛程式設計
  //flutter: 哈哈哈哈
複製程式碼

字串的格式化

在Dart 中用 ${} 來進行字串的格式化,例子如下:

  void main() {
    var a = "熱愛程式設計";
    var b = '哈哈哈哈';
    var c =  "我們都  ${a + b} ";
    print(c);
 }

//輸出結果為
//flutter: 我們都  熱愛程式設計哈哈哈哈
複製程式碼

上面的例子中字串 a 和 b 可以用 + 號 直接拼接在一起

在字串中可以用反斜槓\來進行字元轉譯

字串的相關方法使用例子如下:

   void main() {
    var a = "熱愛程式設計";
    //判斷是否為空
    print(a.isEmpty);
    //字串的長度
    print(a.length);
    //字串的型別
    print(a.runtimeType);
  }

 //輸出結果為:
 //flutter: false
 //flutter: 4
 //flutter: String
複製程式碼

上面例子是字串的常用方法,isEmpty是判斷字串是否為空,length是求字串的長度,runtimeType是求字串的型別。

字串也是一種集合型別,例子如下:

  void main() {
    var a = "熱愛程式設計";
    print(a[1]);
  }
  //輸出為:
  //flutter: 愛
複製程式碼
  1. bool布林型別

Dart中的布林型別只有 true和false,例子如下:

 void main() {
    var a = false;
    print(a.runtimeType);
 }
 //輸出結果:
 //flutter: bool
複製程式碼

4.List列表型別(陣列型別)

用List來定義列表,可以在<>內指定列表元素的資料型別,例子如下:

  void main() {
    List<int> a = [10,100,1000];
    List<String> b = ["熱", "愛","編","程"];
  }
複製程式碼

上面例子中,尖括號中的型別用來指定元素的資料型別,如果列表指定了元素的資料型別,就只能存放該種資料型別的資料。如果想在列表中存放不同型別的資料,可以將列表中元素的型別用dynamic關鍵字宣告為動態型別的,例子如下:

  void main() {
    List<dynamic> a = [10,"哈哈哈",99.9];
  }
複製程式碼

但是在一般開發中我們不需要指定列表的元素型別,因為Dart是可以型別推斷的,所以直接使用var進行宣告即可,上面的例子一般如下宣告:

  void main() {
    var a = [10,"哈哈哈",99.9];
  }
複製程式碼

列表中的常用方法的使用例子如下:

  void main() {
    var a = [10,"哈哈哈",99.9];
    //新增元素
    a.add("ccc");
    //刪除一個元素
    a.remove(10);
    //元素個數
    a.length;
    //...等等其他方法
  }
複製程式碼
  1. Map字典型別

字典定義使用例子如下:

  void main() {
    Map<String, dynamic> a = {"name": "Flutter" , "languge": "Datr"};
  }
複製程式碼

用Map來定義一個字典,在尖括號內來指定字典的key和value的資料型別,需要主要的是和陣列一樣,一旦型別被確定,那麼就必須要和定義的型別一致否則會報錯。

因為 Dart是可以型別推斷的,所以上面的例子可以直接用var來定義如下:

void main() {
  var a = {"name": "Flutter" , "languge": "Datr"};
  print(a);
}
//輸出為:
//flutter: {name: Flutter, languge: Datr}
複製程式碼

Map可以通過鍵來獲取,設定,新增值,例子如下:

void main() {
  var a = {"name": "Flutter" , "languge": "Datr"};
  //新增鍵值對
  a["version"] = "1.1.0";
  //修改鍵值
  a["name"] = "Swift";
  print(a);
}
//輸出結果:
//flutter: {name: Swift, languge: Datr, version: 1.1.0}
複製程式碼

三、Dart中的運算子

1.算數運算子加"+",減 "-" ,乘"*" ,除"/",取整 "~/",取模%

"+"是用來做加的運算,除了數字型別外,字串,列表,字典也支援相加運算,例子如下:

    void main() {

      var a = 10 + 20;
      var b = "10"  + "10";
      print(a);
      print(b);

   }

   //列印結果:
   //flutter: 30
   //flutter: 1010
複製程式碼

"~/" 是取整的運算子,例子如下:

    void main() {
      var a = 15;
      var b =  a ~/ 4;
      print(b);
    }
    //列印結果:
    //flutter: 3
複製程式碼

再其他運算子與其他程式語言基本一樣不做介紹

  1. 比較運算子 == ,!= ,> , < , >= ,<=

與其他語言基本一樣不做介紹

3.型別運算子 as,is, is!

as是做型別的轉換

is是判斷是否屬於某個型別

is!是判斷是否不屬於某個型別

例子如下:

    void main() {

        var dogA = Dog();
        var dogB = dogA;
        
        //
        if (dogB is Dog ){
            dogB.func_swim();
        }

        //用as來簡化上面的程式碼結果一樣
        (dogB as Dog).func_swim();

   }
   
   //列印結果;
   //flutter: 游泳
   //flutter: 游泳
複製程式碼

上面的例子中 可以用as來簡化程式碼。

  1. ??

“??” 是Dart的空條件運算子,就是取預設值的意思,例子如下

    void main() {
        var a;
        var b = a ?? 1;
        print(b);
    }
    //輸出結果:
    //flutter: 1
複製程式碼

上面的例子中, 變數a沒有賦值所以預設為null,在將a賦值給b的時候因為a是null,所以 通過?? 給把1賦值給了a。

5.級聯運算子 “..”

級聯運算子可以對某個物件進行連續的操作而不用生成中間變數,例子如下: 例子一

  class Person{

    func_one(){
      print("Dart語言");
    }

     func_two(){
      print("Flutter使用Dart");
     }
  }

  void main() {
    Person()..func_one()..func_two();
  }
  //列印結果如下:
  //flutter: Dart語言
  //flutter: Flutter使用Dart
複製程式碼
  1. 點運算子以及“?.”的使用

點運算子用來訪問物件的屬性或方法,對不確定是否為null的物件可以用“?.”來進行操作,例子如下:

  class Person{
    var name;

  }

  void main() {
    var p = Person();
    print(p?.name);
  }
複製程式碼

四、 函式

1.函式的一般書寫格式:

返回值  函式名稱(引數列表){
    函式體
}
複製程式碼

例子如下:

  void main() {

    int func_add(int a,int b){
      return a + b;
    }

    var c = func_add(1, 2);
    print(c);
  }
  //列印結果:
  //flutter: 3
複製程式碼

上面例子中main函式是程式的入口, 裡面定義了func_add函式

Dart中的all is物件, 所以可以將函式賦值給一個變數或者將函式作為引數,例子如下;

  void main() {

    int func_add(int a,int b){
      return a + b;
    }

    var c = func_add;
    var d = c(1,2);
    print(d);
 }
複製程式碼

Dart語言中在定義函式的時候函式的引數型別和返回值型別都可以省略,Dart語言會根據傳入的引數和返回的值來動態推斷。例子如下:

  void main() {

    func_add(a,b){
      return a + b;
    }

    var c =  func_add(1, 2);
    print(c);
}
//列印結果
//flutter: 3
複製程式碼

如果某個函式的函式體只有一句話可以用箭頭函式來定義,例子如下:

  void main() {

    func_add(a,b) => a + b;

    var c =  func_add(1, 2);
    print(c);
  }
  //輸出結果:
  //flutter: 3
複製程式碼

2.可選引數的函式定義

名稱可選引數函式的一般格式為

 返回值型別 函式名稱({可選引數列表}){
      函式體
  }
複製程式碼

可選引數放在{}號內部,例子如下:

  void main() {

    func_text({a,b}) {

      if(a != null){
          print(a);
      }

      if(b != null){
         print(b);
      }

     };

     func_text(a: 2);
 }
 //列印結果
 //flutter: 2
 
 上面的例子中定義了函式func_text其中引數 a和b都是可選的,需要注意的是,在呼叫的時候需要引數名稱加:的形式來進行傳引數
複製程式碼

位置可選引數,只需要將可選引數放入中括號即可,例子如下;

  void main() {

    func_text(a, [b]) {

      if(a != null){
        print(a);
      }

      if(b != null){
       print(b);
      }

    };

    func_text(2,3);

  }
  //輸出結果
  //flutter: 2
  //flutter: 3
複製程式碼

在上面例子中func_text中有兩個引數a和b,其中b 是可選的。在呼叫的時候可以不傳。

函式可選的可以給個預設值,如果沒有預設值函式中取到的引數值為null,,設定預設值以後如果呼叫的時候沒有傳入這個引數,在函式內就會使用預設值,在定義可選引數的時候應該儘量提供一個預設值。

例子如下:

  void main() {

      func_text(a, [b = 4]) {

       if(a != null){
          print(a);
        }

        if(b != null){
           print(b);
        }

       };

      func_text(3);
  }
  
  //列印如下:
  //flutter: 3
  //flutter: 4
複製程式碼

3、匿名函式

Dart中沒有名稱的函式是匿名函式,匿名函式可以直接賦值給變數,通過變數來呼叫。例子如下:

  void main() {

    var a = (b,c){
      return b + c;
    };

    var d = a(1,2);
    print(d);
  }
  //列印如下:
  //flutter: 3
複製程式碼

在上面的例子中,把匿名函式賦值給了變數a,然後通過a來呼叫。

五、閉包

閉包是一種特殊的函式。

閉包是定義在函式內部的函式。

閉包能夠訪問外部方法內的區域性變數並持有。

經典例子如下:

  void main() {

    var  func = a();
    func();
    func();
    func();
  }

  a(){
    int count = 0;

    func_count(){
       print(count ++);
    }
    return func_count;
 }
 //列印結果:
 //flutter: 0
 //flutter: 1
 //flutter: 2
複製程式碼

上面例子中, 函式a中的 func_count函式就是閉包,他定義在a函式內,能夠訪問並持有他外部函式的區域性變數count,暫時理解到這裡後面會詳細說明閉包的使用。

六、類

Dart是基於類和繼承的物件導向的語言。物件是類的例項。在類中定義了物件的屬性和方法。

  1. 自定義類和類的建構函式

Dart中用 class關鍵字來進行類的定義,例子如下:

class Person {
    
    double weight;
    int age;
}
複製程式碼

上面的例子中定義了Person類,類中定義了兩個屬性weight和age;我們可以通過Person來建立物件,通過類來建立物件需要呼叫類的建構函式。類的建構函式一般和類的名字一樣。當定義一個類時Dart會預設生成一個沒有引數的建構函式,可以直接通過類的名稱來呼叫。例子如下:

    class Person{
          var name;

     }

  void main() {
    var p = Person();
    print(p?.name);
  }
複製程式碼

上面的例子中,定義的Person類可以直接通過Person()來建立物件。類物件中的方法屬性都可以通過點來訪問呼叫。

一般Dart語言的構造方法的書寫格式如下:

    class Person{
          var name;
          var age;
          
          //一般構造方法的書寫格式
          Person(this.name,this.age);

     }
複製程式碼

2.類的例項方法:

類定義了屬性和方法,一般屬性用來儲存資料,方法用來定義行為。

例子如下:

 class Person{
          var name;
          var age;
          
          //一般構造方法的書寫格式
          Person(this.name,this.age);
          
          func_run(){
             print("在跑步");
          }
}
複製程式碼

上面的例子中定義了方法func_run()就是Person類中的方法。呼叫的例子如下:

void main() {
    var p = Person();
    p.func_run();
}
複製程式碼

在類中用this來訪問自身的屬性和方法,例子如下:

  class Person{
          var name;
          var age;
          
          //一般構造方法的書寫格式
          Person(this.name,this.age);
          
          func_run(){
             print(" ${this.name}  在跑步"); //用this訪問name屬性
          }
}
複製程式碼

類中還有兩個比較特殊的方法,Setters 和 Getters方法,Setters用來設定物件的屬性,Getters用來獲取物件的屬性。在定義屬性時Dart會預設生成Setters和Getters方法。

  1. 抽象類和抽象方法

Dart中 在抽象類中可以定義抽象方法,抽象方法是隻有定義沒有函式實現的方法。抽象方法是面向介面開發的基礎。

抽象類用abstract關鍵字來定義。例子如下:

    abstract class PersonInterface{
         func_run();
   }
複製程式碼

上面例子中定義了一個PersonInterface 的介面,裡面只定義了一個func_run()的抽象方法。Person類可以對這個介面進行實現例子如下,用關鍵詞implements來實現一個介面例子如下:

 abstract class PersonInterface{
         func_run();

 }
 
 class Person implements PersonInterface{
          var name;
          var age;
          
          //一般構造方法的書寫格式
          Person(this.name,this.age);
          
          實現介面函式
          func_run(){
             print(" ${this.name}  在跑步"); //用this訪問name屬性
          }
}
複製程式碼

一個類也可以同時實現多個介面。

抽象類不可以被例項化。

  1. 類的繼承

子類繼承父類,就可以直接使用父類中的屬性和方法。並且子類可以重寫父類中的屬性和方法。Dart中用extends關鍵字來進行類的繼承。例子如下:

  class Person{
          var name;
          var age;
          //一般構造方法的書寫格式
          Person(this.name,this.age);
          
          func_run(){
             print("在跑步");
          }
}

class Man extends  Person{
    
    //建構函式呼叫夫類的建構函式
    Man(name,age) : super(name,age);
    
    func_eat(){
        print("正在吃飯");
    }
    
}
複製程式碼

上面的例子中Man類繼繼承了Person類,需要注意的是建構函式不能被繼承,但可以通過super來呼叫父類的方法。子類也可以過載父類的方法。例子如下:

  class Person{
          var name;
          var age;
          //一般構造方法的書寫格式
          Person(this.name,this.age);
          
          func_run(){
             print("在跑步");
          }
}

class Man extends  Person{
    
    //建構函式呼叫夫類的建構函式
    Man(name,age) : super(name,age);
    
    func_eat(){
        print("正在吃飯");
    }
    
    @override
    func_run(){
        print("Man在跑步");
    }

}
複製程式碼

上面例子中子類過載父類的func_run()方法,其中@override關鍵字用來標註這個方法是子類過載父類的,@override關鍵字可以省略。

  1. 列舉

列舉用enum來定義。例子如下:

  enum  Language{
      Dart,
      Oc,
      Swift
  }


  class Person{
          var name;
          Language language;
          
          //一般構造方法的書寫格式
          Person(this.name,this.language);

 }
    
    
    void main() {
         var p = Person();
         p.language = Language.Dart;
         print(p.language);
   } 
   
   //輸出:
   //Language.Dart
複製程式碼

7、 類的Mixin特性

Mixin是Dart中非常強大的一個功能。Dart語言是單繼承的只能繼承一個父類。很多時候需要集合多個類的功能來實現一個複雜的自定義類,這時候Mixin特性就不錯。

Mixin的功能就是讓一個類把其他類的功能混合進來。例子如下:

 mixin Walker{

      func_walk(){

       print("跑步");
      }
 }

  mixin Swim{

    func_swim(){

      print("游泳");
    }
 }

 mixin Flying{

    func_flying(){

       print("飛");
    }
  }

  class Dog with Swim, Walker {


   }


   void main() {

      var dog =  Dog();

      print(dog.func_walk());
      print(dog.func_swim());

   }
複製程式碼

程式執行結果:

//flutter: 跑步

//flutter: 游泳

在上面例子中定義了,mixin的跑Walker和游泳Swim,然後讓Dog類通過with 來遵守。Dog類就有了Walker和Swim裡面的功能。

能被用來混合的類是Mixin類,Mixin類不能實現構造方法否則不能被其他類混合,用with關鍵字來進行混合。Mixin也支援多混合。

  1. 範型

例子如下:

 class Person<T>{
          T data;   
          //一般構造方法的書寫格式
          Person(this.data);
 }
 
 void main() {

     var p =Person("xiaoming");
     print(p.data);
     //列印結果:
     //flutter: xiaoming
 }
複製程式碼

七、Dart非同步程式設計 async , await , Future的使用

在Dart語言中可以通過 async , await 關鍵字來編寫非同步執行的程式碼。也可以通過Future相關方法處理非同步任務。

  1. async 和await關鍵字的使用

     void main() {
    
          requestData();
          print("繼續執行程式");
    
     }
    
    requestData(){
    
      print("收到資料");
    }
    複製程式碼

呼叫 上面函式的列印結果是:

flutter: 收到資料

flutter: 繼續執行程式

可以看出上面例子中的函式是按順序執行的。如果我們模擬真實的網路請求,那麼requestData會有一定的耗時,即應該後列印“收到資料”,先列印“繼續執行程式”。這時候我們就需要用到非同步處理,對上面的例子修改如下:

    void main() {

       requestData();
       print("繼續執行程式");

   }

    requestData() async {

      var data = await "收到的資料";
      print(data);
    }
複製程式碼

上面程式執行結果為:

//flutter: 繼續執行程式

//flutter: 收到的資料

現在可以看出是先列印了“繼續執行程式”,後列印了“收到的資料”。實現了非同步的效果。

被非同步執行的函式需要用async關鍵字來修飾,且在函式內需要進行滯後處理的語句要用await關鍵字來修飾如上面例子中的 requestData()函式用 async關鍵字修飾, 函式內部 "收到的資料"前用await修飾。

  1. 非同步和回撥的使用

非同步和回撥一般都是結合在一起來使用的。如上面的例子中,先從網路請求中獲取資料, 接下來把拿到的資料渲染到UI介面上。就是一個非同步回撥的使用例子。該例子如下:

   void main() {

       requestData(refreshUI);
       print("繼續執行程式");

   }

    refreshUI(data){
       print(data);
       print("重新整理UI介面");
    }

    requestData(callBack) async {

       var data = await "服務端返回的Json資料";
       callBack(data);
    }
複製程式碼

上面程式的執行結果是:

//flutter: 繼續執行程式

//flutter: 服務端返回的Json資料

//flutter: 重新整理UI介面

在Dart中函式可以作為引數,在上面的例子中將refreshUI函式當做引數傳給requestData,在後在requestData中拿到資料data後呼叫。

  1. Future的使用

任意一個 async函式都會返回一個Future物件。我們可以通過Future 的then方法來設定回撥。上面的例子可以改寫為:

   void main() {

      var future =  requestData();
      future.then( (data){

        refreshUI(data);
 
        });
        print("繼續執行程式");

    }

   refreshUI(data){
     print("重新整理UI介面 ${data}");
   }

   requestData() async {

       var data = await "服務端返回的Json資料";
       return data;
  }
複製程式碼

程式執行輸出結果:

//flutter: 繼續執行程式

//flutter: 重新整理UI介面 服務端返回的Json資料

八、模組的引用

1.用 import來倒入模組

例子:

在lib 資料夾下建立aa.dart檔案,其中aa.dart可以作為模組,在aa.dart中編寫如下程式碼:

void  print_func(){
    
    print("aa檔案的函式");
}
複製程式碼

在程式的main.dart檔案中匯入aa.dart檔案,就可以呼叫aa.dart檔案中的print_func()函式了,例子如下:

import "./lib.aa.dart";

main(){
    
     print_func();
     //列印結果:
     //aa檔案的函式
}
複製程式碼

import 關鍵字用來匯入模組,也可以選擇只匯入某個模組的某一部分,例子如下:

在上面例子中的aa.dart 檔案中新增一個func_run(),func_eat()函式

    void  print_func(){
    
        print("aa檔案的函式");
    
   }

    void func_run(){
    
        pint("我在跑步");
   }
   
   void func_eat(){
       print("在吃飯");
   }
複製程式碼

在main.dart 中用關鍵字show只匯入aa.dart 中的run_func()部分,如果要匯入多個內容,可以使用逗號分割開即可,main.dart中的程式碼如下:

    import "./lib.aa.dart" show run_func ;
    
    main(){
        run_func();
        //列印結果:
        //我在跑步
    }
複製程式碼

2.模組的重新命名

如果在不同的Dart檔案中定義了相同名稱的函式,將這些檔案匯入並呼叫這個函式的時候就會出錯,這時候我們可以用 as關鍵字來對模組進行重新命名的方式避免錯誤。例子如下:

在lib資料夾下新建一個bb的檔案,在裡面寫如下程式碼:

 bb.dart檔案中寫入:
 
    void  print_func(){
    
        print("bb檔案的函式");
    
    }


在main.dart中寫如下使用:


    import "./lib.aa.dart";
    import "./lib.bb.dart";
     
    
    main(){
        print_func();
        //執行就會報錯
    }
複製程式碼

對於上面的錯誤可以通過用as關鍵字對模組重新命名來避免。例子如下:

在main.dart檔案中

    import "./lib.aa.dart";
    import "./lib.bb.dart" as bb;
     
    
    main(){
        print_func(); //aa.dart中的
        bb.print_func(); //bb.dart中的
        //列印結果:
        //aa檔案的函式
        //bb檔案的函式
    }
複製程式碼

簡單的學習筆記

文章預告,下一篇寫Flutter常用控制元件的使用以及佈局

相關文章