Flutter學(xué)習(xí)(二)Dart語(yǔ)法

簡(jiǎn)介

Dart 在靜態(tài)語(yǔ)法方面和 Java 非常相似,如類型定義、函數(shù)聲明、泛型等,而在動(dòng)態(tài)特性方面又和 JavaScript 很像,如函數(shù)式特性、異步支持等。除了融合 Java 和 JavaScript 語(yǔ)言之所長(zhǎng)之外,Dart 也具有一些其他很有表現(xiàn)力的語(yǔ)法,如可選命名參數(shù)、..(級(jí)聯(lián)運(yùn)算符)和?.(條件成員訪問(wèn)運(yùn)算符)以及??(判空賦值運(yùn)算符)。

一、變量聲明

1.var 關(guān)鍵字

類似于 JavaScript 中的var,它可以接收任何類型的變量,但最大的不同是 Dart 中 var變量一旦賦值,類型便會(huì)確定,則不能再改變其類型,如:

var t = "hi world";
// 下面代碼在dart中會(huì)報(bào)錯(cuò),因?yàn)樽兞縯的類型已經(jīng)確定為String,
// 類型一旦確定后則不能再更改其類型。
t = 1000;

上面的代碼在 JavaScript 是沒(méi)有問(wèn)題的,前端開(kāi)發(fā)者需要注意一下,之所以有此差異是因?yàn)?Dart 本身是一個(gè)強(qiáng)類型語(yǔ)言,任何變量都是有確定類型的,在 Dart 中,當(dāng)用var聲明一個(gè)變量后,Dart 在編譯時(shí)會(huì)根據(jù)第一次賦值數(shù)據(jù)的類型來(lái)推斷其類型,編譯結(jié)束后其類型就已經(jīng)被確定,而 JavaScript 是純粹的弱類型腳本語(yǔ)言,var只是變量的聲明方式而已。

2.dynamic 和 Object

Object 是 Dart 所有對(duì)象的根基類,也就是說(shuō)在 Dart 中所有類型都是Object的子類(包括FunctionNull),所以任何類型的數(shù)據(jù)都可以賦值給Object聲明的對(duì)象。 dynamicObject聲明的變量都可以賦值任意對(duì)象,且后期可以改變賦值的類型,這和var是不同的,如:

dynamic t;
Object x;
t = "hi world";
x = 'Hello Object';
//下面代碼沒(méi)有問(wèn)題
t = 1000;
x = 1000;

dynamicObject不同的是dynamic聲明的對(duì)象編譯器會(huì)提供所有可能的組合,而Object聲明的對(duì)象只能使用Object的屬性與方法, 否則編譯器會(huì)報(bào)錯(cuò),如:

dynamic a;
Object b = "";
main() {
   a = "";
   printLengths();
}   
printLengths() {
  // 正常
  print(a.length);
  // 報(bào)錯(cuò) The getter 'length' is not defined for the class 'Object'
  print(b.length);
}

dynamic的這個(gè)特點(diǎn)使得我們?cè)谑褂盟鼤r(shí)需要格外注意,這很容易引入一個(gè)運(yùn)行時(shí)錯(cuò)誤,比如下面代碼在編譯時(shí)不會(huì)報(bào)錯(cuò),而在運(yùn)行時(shí)會(huì)報(bào)錯(cuò):

print(a.xx); // a是字符串,沒(méi)有"xx"屬性,編譯時(shí)不會(huì)報(bào)錯(cuò),運(yùn)行時(shí)會(huì)報(bào)錯(cuò)
3.final和const

如果從未打算更改一個(gè)變量,那么使用finalconst,不是var,也不是一個(gè)類型。 一個(gè)final變量只能被設(shè)置一次,兩者區(qū)別在于:const 變量是一個(gè)編譯時(shí)常量(編譯時(shí)直接替換為常量值),final變量在第一次使用時(shí)被初始化。被final或者const修飾的變量,變量類型可以省略,如:

//可以省略String這個(gè)類型聲明
final str = "hi world";
//final String str = "hi world"; 
const str1 = "hi world";
//const String str1 = "hi world";
4.空安全(null-safety)

Dart 中一切都是對(duì)象,這意味著如果我們定義一個(gè)數(shù)字,在初始化它之前如果我們使用了它,假如沒(méi)有某種檢查機(jī)制,則不會(huì)報(bào)錯(cuò),比如:

test() {
  int i; 
  print(i*8);
}

在 Dart 引入空安全之前,上面代碼在執(zhí)行前不會(huì)報(bào)錯(cuò),但會(huì)觸發(fā)一個(gè)運(yùn)行時(shí)錯(cuò)誤,原因是 i 的值為 null 。但現(xiàn)在有了空安全,則定義變量時(shí)我們可以指定變量是可空還是不可空。

int i = 8; //默認(rèn)為不可空,必須在定義時(shí)初始化。
int? j; // 定義為可空類型,對(duì)于可空變量,我們?cè)谑褂们氨仨毰锌铡?
// 如果我們預(yù)期變量不能為空,但在定義時(shí)不能確定其初始值,則可以加上late關(guān)鍵字,
// 表示會(huì)稍后初始化,但是在正式使用它之前必須得保證初始化過(guò)了,否則會(huì)報(bào)錯(cuò)
late int k;
k=9;

如果一個(gè)變量我們定義為可空類型,在某些情況下即使我們給它賦值過(guò)了,但是預(yù)處理器仍然有可能識(shí)別不出,這時(shí)我們就要顯式(通過(guò)在變量后面加一個(gè)”!“符號(hào))告訴預(yù)處理器它已經(jīng)不是null了,比如:

class Test{
  int? i;
  Function? fun;
  say(){
    if(i!=null) {
      print(i! * 8); //因?yàn)橐呀?jīng)判過(guò)空,所以能走到這 i 必不為null,如果沒(méi)有顯式申明,則 IDE 會(huì)報(bào)錯(cuò)
    }
    if(fun!=null){
      fun!(); // 同上
    }
  }
}

上面中如果函數(shù)變量可空時(shí),調(diào)用的時(shí)候可以用語(yǔ)法糖:

fun?.call() // fun 不為空時(shí)則會(huì)被調(diào)用

二、函數(shù)

Dart是一種面向?qū)ο蟮恼Z(yǔ)言,所以即使是函數(shù)也是對(duì)象,并且有一個(gè)類型Function。這意味著函數(shù)可以賦值給變量或作為參數(shù)傳遞給其他函數(shù),這是函數(shù)式編程的典型特征。

1.函數(shù)聲明
bool isNoble(int atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}

Dart函數(shù)聲明如果沒(méi)有顯式聲明返回值類型時(shí)會(huì)默認(rèn)當(dāng)做dynamic處理,注意,函數(shù)返回值沒(méi)有類型推斷

typedef bool CALLBACK();

//不指定返回類型,此時(shí)默認(rèn)為dynamic,不是bool
isNoble(int atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}

void test(CALLBACK cb){
   print(cb()); 
}
//報(bào)錯(cuò),isNoble不是bool類型
test(isNoble);

對(duì)于只包含一個(gè)表達(dá)式的函數(shù),可以使用簡(jiǎn)寫(xiě)語(yǔ)法:

bool isNoble (int atomicNumber)=> true ;   
2.函數(shù)作為變量
var say = (str){
  print(str);
};
say("hi world");
3.函數(shù)作為參數(shù)傳遞
//定義函數(shù)execute,它的參數(shù)類型為函數(shù)
void execute(var callback) {
    callback(); //執(zhí)行傳入的函數(shù)
}
//調(diào)用execute,將箭頭函數(shù)作為參數(shù)傳遞
execute(() => print("xxx"))
(1)可選的位置參數(shù)

包裝一組函數(shù)參數(shù),用[]標(biāo)記為可選的位置參數(shù),并放在參數(shù)列表的最后面:

String say(String from, String msg, [String? device]) {
  var result = '$from says $msg';
  if (device != null) {
    result = '$result with a $device';
  }
  return result;
}

下面是一個(gè)不帶可選參數(shù)調(diào)用這個(gè)函數(shù)的例子:

say('Bob', 'Howdy'); //結(jié)果是: Bob says Howdy

下面是用第三個(gè)參數(shù)調(diào)用這個(gè)函數(shù)的例子:

say('Bob', 'Howdy', 'smoke signal'); //結(jié)果是:Bob says Howdy with a smoke signal

(2)可選的命名參數(shù)

定義函數(shù)時(shí),使用{param1, param2, …},放在參數(shù)列表的最后面,用于指定命名參數(shù)。例如:

//設(shè)置[bold]和[hidden]標(biāo)志
void enableFlags({bool bold, bool hidden}) {
    // ... 
}

調(diào)用函數(shù)時(shí),可以使用指定命名參數(shù)。例如:paramName: value

enableFlags(bold: true, hidden: false);

可選命名參數(shù)在Flutter中使用非常多。**注意,不能同時(shí)使用可選的位置參數(shù)和可選的命名參數(shù)。

三、mixin

Dart 是不支持多繼承的,但是它支持 mixin,簡(jiǎn)單來(lái)講 mixin 可以 “組合” 多個(gè)類,我們通過(guò)一個(gè)例子來(lái)理解。
定義一個(gè) Person 類,實(shí)現(xiàn)吃飯、說(shuō)話、走路和寫(xiě)代碼功能,同時(shí)定義一個(gè) Dog 類,實(shí)現(xiàn)吃飯、和走路功能:

class Person {
  say() {
    print('say');
  }
}

mixin Eat {
  eat() {
    print('eat');
  }
}

mixin Walk {
  walk() {
    print('walk');
  }
}

mixin Code {
  code() {
    print('key');
  }
}

class Dog with Eat, Walk{}
class Man extends Person with Eat, Walk, Code{}

下一篇:異步線程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容