【Flutter 1-9】Flutter教程Dart語言——函數和匿名函數

作者 | 弗拉德
來源 | 弗拉德(公衆號:fulade_me)

Dart 同樣也是一種面向對象的語音。所以即便函數也是一個對象。類型爲 Function,這意味着函數可做作爲變量,也也可以作爲函數的參數。

函數

下面是定義一個函數的例子:

isEmpty(List aList) {
  return aList.length == 0;
}

爲了規範其實我們需要在函數的頭部聲明一下返回值類型,當然如果不聲明也可以運行,

bool isEmpty(List aList) {
  return aList.length == 0;
}

如果函數體內只包含一個表達式,你可以使用簡寫語法:

bool isEmpty(List aList) => aList == 0;

=> 表達的 是 { return 表達式; } 的簡寫,有時=>也稱之爲胖箭頭語法

參數

函數可以有兩種形式的參數:必選參數可選參數。必選參數定義在參數列表前面,可選參數一定是定義在必要參數後面。

可選的命名參數

當你調用函數時,可以使用 參數名: 參數值 的形式來指定命名參數。例如:

enableFlags(bold: true, hidden: false);

已命名的參數是可選參數了,除非他們被特別標記爲 required

定義函數時,使用 {param1, param2, …} 來指定命名參數:

/// 設置 [bold] 和 [hidden] 標識……
void enableFlags({bool bold, bool hidden}) {...}

雖然命名參數是可選參數的一種類型,但是你仍然可以使用 @required 註解來標識一個命名參數是必須的參數,此時調用者則必須爲該參數提供一個值。例如:

const Scrollbar({Key key, @required Widget child})

如果調用者想要通過 Scrollbar 的構造函數構造一個 Scrollbar 對象而不提供 child 參數,則會導致編譯錯誤。

可選參數

使用 [] 將一系列參數包裹起來作爲可選參數:

strings(String s1, String s2, [String s3]) {
  var result = '$s1 and $s2';
  if (s3 != null) {
    result = '$result and $s3';
  }
  print(result);
}

下面是不使用可選參數調用上述函數的示例:

strings("s1", "s2");
s1 and s2

下面是使用可選參數調用上述函數的示例:

strings("s1", "s2", "s3");
s1 and s2 and s3
默認參數值

我們可以用 = 爲函數的命名參數和可選參數定義默認值,默認值必須爲編譯時常量,沒有指定默認值的情況下默認值爲 null

下面是設置可選參數默認值示例:

/// 設置 [bold] 和 [hidden] 標識……
void enableFlags({bool bold = false, bool hidden = false}) {...}

// bold 的值將爲 true;而 hidden 將爲 false。
enableFlags(bold: true);

下一個示例 默認值:

strings(String s1, String s2, [String s3 = 'this is s3', String s4]) {
  var result = '$s1 and $s2';
  if (s3 != null) {
    result = '$result and $s3';
  }
  if (s4 != null) {
    result = '$result and $s4';
  }
  print(result);
}

strings("s1", "s2");
s1 and s2 and this is s3
main() 函數

每個 Dart 程序都必須有一個 main() 頂級函數作爲程序的入口,main() 函數返回值爲 void

下面是一個 Flutter 應用的 main() 函數示例:

void main() {
  runApp(MyApp());
}
函數作爲參數

可以將函數作爲參數傳遞給另一個函數。例如:

void printElement(int element) {
  print(element);
}
// 將 printElement 函數作爲參數傳遞。
var list = [1, 2, 3];
list.forEach(printElement);

你也可以將函數賦值給一個變量,比如:

var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
var result = loudify('hello');
print(result);

匿名函數

大多數方法都是有名字的,比如 main()printElement()。你可以創建一個沒有名字的方法,稱之爲 匿名函數,其實匿名函數很常見,也有不同的叫法,在C++裏面叫Lambda表達式,在Objective-C叫Block閉包。你可以將匿名方法賦值給一個變量然後使用它。

匿名方法看起來與命名函數h類似,在括號之間可以定義參數,參數之間用逗號分割。

後面大括號中的內容則爲函數體:

([[類型] 參數[, …]]) {
  函數體;
};

下面代碼定義了只有一個參數 item 且沒有參數類型的匿名方法。List 中的每個元素都會調用這個函數,打印元素位置和值的字符串:

var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
  print('${list.indexOf(item)}: $item');
});

如果函數體內只有一行語句,你可以使用胖箭頭縮寫法。下面代碼的運行結果,與上面代碼的運行結果是一致的。

list.forEach(
    (item) => print('${list.indexOf(item)}: $item'));

變量作用域

變量的作用域在寫代碼的時候就確定了,大括號內定義的變量只能在大括號內訪問,與 Java 類似。

下面是一個嵌套函數中變量在多個作用域中的示例:

bool topLevel = true;

void main() {
  var insideMain = true;

  void myFunction() {
    var insideFunction = true;

    void nestedFunction() {
      var insideNestedFunction = true;

      assert(topLevel);
      assert(insideMain);
      assert(insideFunction);
      assert(insideNestedFunction);
    }
  }
}

注意 nestedFunction() 函數可以訪問包括頂層變量在內的所有的變量。

返回值
所有的函數都有返回值。沒有顯示返回語句的函數最後一行默認爲執行 return null;。

foo() {}

assert(foo() == null);

本文所有代碼都已上傳到Github


公衆號

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章