flutter開發之——Dart中的函式

白瑞德發表於2019-08-20

前言

Dart是一個真正的面嚮物件語言,方法也是物件並且具有一種型別Function。 這意味著,方法可以賦值給變數,也可以當做其他方法的引數。 也可以把Dart類的例項當做方法來呼叫。大家可以通過閱讀lambda表示式與Kotlin高階函式Kotlin中的函式類似對比學習。首先通過hello world瞭解一下Dart中的函式:

_printHello("白瑞德");
void _printHello(String name) {
  print("hello: ${name}");
}
>>> hello: 白瑞德
複製程式碼

注意:Dart沒有public、protected、private的概念。但是如果變數或函式以下劃線_開始,則該函式或變數屬於這個包私有(private)的方法。

函式的定義

函式定義指定特定任務的執行方式。在使用函式之前,必須先定義它。dart中函式的定義和Java中的類似。由函式入參、返回結果型別和函式體組成

String function_name(String parma) { 
   //statements 
}

void function_name(String parma) { 
   //statements 
}

function_name(parma) { 
   //statements 
   return 2;
}
複製程式碼

其中void關鍵字表示該函式不向滴啊用這返回任何值,可以省略不寫。函式的入參也可以忽略引數型別,這樣函式預設接受dynamic型別的引數,也就是任何型別都可以傳遞。當省略了返回值型別的時候,也會預設返回值的型別為dynamic。 注意:dynamic型別可能會帶來執行時異常:

_printInt(int name) {
  return "Hello";
}

_printInt(_printInt(2))
複製程式碼

這段程式碼會報:type 'String' is not a subtype of type 'int'。 注意:上述三個function_name是不可以出現在同一個程式碼塊裡,有Java開發經驗的一定知道這種形式就是Java函式的過載,但這在Dart裡是行不通的,Dart裡有其他方式實現這種過載。 對於只有一個表示式的方法,可以選擇使用縮寫語法來定義: String function_name(name) => name+name; 函式體只能是一個表示式,不能使用語句(if-else)

可選引數

Dart中沒有類似Java過載的函那樣的函式,我們可以使用可選引數來實現類似的功能。 可選引數可以是命名引數或者基於位置的引數,但是這兩種引數不能同時當做可選引數。

可選命名引數

呼叫方法的時候,你可以使用這種形式paramName: value來指定命名引數。一個函式可以同時擁有可選引數和必選引數,但是必選引數必須在最前面 例如:

_printInt(age: 19,address: "粵海街道");
_printHello("白瑞德",age: 19);
_printInt({int age,String address}) {
  ...
}
_printHello(name,{int age,String address}) {
  ...
}
複製程式碼

在可選引數的時候,可以使用=來定義可選引數的預設值。預設值只能是編譯時常量。如果沒有提供預設值,則預設值為null。

//年齡預設為7,而address預設為null
_printHello(name,{int age = 7,String address}) {
    ...
}
複製程式碼

可選位置引數

把一些方法的引數放到[]中就變成可選位置引數了:

_printString("白瑞德");
_printString([String name,int age = 7,String address]){
      ...
}
複製程式碼

可選的命名引數的宣告使用“{}”,使用“:”指定預設值,可選的位置函式的宣告使用“[]”,使用“=”指定預設值。

過載與構造方法

Dart語言是同名函式的,即使入參不同。那麼問題就來了,建構函式怎麼辦?難道只能一個建構函式嗎?答案是否定的。 Dare支援命名建構函式,使用命名建構函式可以為一個類實現多個建構函式, 或者使用命名建構函式來更清晰的表明你的意圖:

class User {
  String name;
  User.init();
  User.initName(name){
    this.name = name;
  }
}
複製程式碼

注意:建構函式不能繼承,所以超類的命名建構函式 也不會被繼承。如果你希望 子類也有超類一樣的命名建構函式, 你必須在子類中自己實現該建構函式。 預設情況下,子類的建構函式會自動呼叫超類的無名無引數的預設建構函式。 超類的建構函式在子類建構函式體開始執行的位置呼叫。如果提供了一個 initializer list(初始化引數列表),則初始化引數列表在超類建構函式執行之前執行。 下面是建構函式執行順序:

  • initializer list(初始化引數列表)
  • superclass’s no-arg constructor(超類的無名建構函式)
  • main class’s no-arg constructor(主類的無名建構函式)

如果超類沒有無名無引數建構函式,則你需要手工的呼叫超類的其他建構函式。在建構函式引數後使用冒號 (:) 可以呼叫 超類建構函式。 由於超類建構函式的引數在建構函式執行之前執行,所以引數可以是一個表示式或者一個方法呼叫:

class Student extends User{
  Student.init() : super.init();
  Student.initName(name):super.initName(name){
  }
}
複製程式碼

一等方法物件

在Dart中,有一種函式被稱為:Functions as first-class objects一等方法物件。可一把方法當做引數呼叫另外一個方法,也可以把方法賦值給一個變數。

printElement(element) {
  print(element);
}
var list = [1, 2, 3];
list.forEach(printElement);

var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');
複製程式碼

這種將函式作為引數的方式,經常用於子元件和父元件互動。父元件將一個函式作為引數傳遞給子元件。子元件可以直接通過這個函式實現對父元件的通訊。

lambda/匿名函式/閉包

大部分方法都帶有名字。也可以建立沒有名字的方法,稱之為匿名方法,有時候也被稱為Lambda或者閉包,這是一種表示函式的簡介方式。可以把匿名方法賦值給一個變數。

var printName =(num){
    print(num);
    return num;
};
//當只有一行表示式時,可以使用箭頭函式
var printName =(num) => print(num);
複製程式碼

一個閉包是一個方法物件,不管該物件在何處被呼叫,該物件都可以訪問其作用域內的變數。方法可以封閉定義到其作用域內的變數。下面的示例中,makeAdder()捕獲到了變數addBy。不管你在那裡執行makeAdder() 所返回的函式,都可以使用addBy引數。

Function makeAdder(num addBy) {
  return (num i) => addBy + i;
}

main() {
  // Create a function that adds 2.
  var add2 = makeAdder(2);

  // Create a function that adds 4.
  var add4 = makeAdder(4);

  assert(add2(3) == 5);
  assert(add4(3) == 7);
}
複製程式碼

結語

Dart中的函式使用基本講解完畢了,想要進一步瞭解的可以去官方教程上學習

相關文章