(三)Flutter學習之Dart函數

初識 Dart 函數

Dart 是一門徹底的面向對象有語言。甚至函數也是一個對象,它的類型是 Function,這意味着函數能夠賦值給變量,也能夠被做爲參數傳遞給另外一個函數git

下面來看下 Dart 一個簡單的函數:github

bool isEven(int position) {
  return nums[position] % 2 == 0;
}
複製代碼

雖然 Dart 官方不建議省略 type annotation (函數返回類型、變量類型等), 可是 Dart 語法依然容許咱們省略:bash

isEven(int position) {
  return nums[position] % 2 == 0;
}
複製代碼

上面的函數體內只有一個表達式,因此咱們可使用箭頭函數,這樣看上去更加簡潔:閉包

bool isEven(int position) => nums[position] % 2 == 0;
複製代碼

根據官方上對箭頭函數的描述:=> 和 分號 ; 之間只能是一個表達式而不是語句. 好比 =>; 之間不能放 if 語句,但能夠放 條件表達式(condition ? expr1 : expr2)app

可是通過測試發現 =>; 之間一條非控制流語句,如:ide

wrapPrint() => print("fat arrow function");
複製代碼

上面提到 =>; 之間不能放 if語句, 可能開發者再把普通函數改爲箭頭函數忘記了刪除花括號{}函數

test() => {
      if (true) {print("success")}
    };
複製代碼

這不是使用了 if表達式 了嗎?可是上面的例子 =>; 之間實際上是一個 Set 集合, {}不只在定義函數的時候用到,在構建 Set、Map集合字面量 的時候也用到了,而後在構建 Set 字面量的時候使用 if 語句而已(collection if-for), 這些已經在前面的文字講過了:學習

咱們能夠打印一下 test 函數的返回類型就知道了:測試

main() {
  print(test().runtimeType);
}

// 輸出
_CompactLinkedHashSet<Set<void>>
複製代碼

因此上面的例子 =>; 之間依然是一個表達式.ui

可選參數

在調用一個可選參數的函數, 能夠指定指定某個須要傳遞的參數, 或者一個參數都不傳遞

語法格式:funcName(param1, param2, {opt1, opt2, …})

void enableFlags({bool bold, bool hidden}) {}

main() {
  enableFlags(bold: false);
  enableFlags(bold: false);
  enableFlags(bold: false,hidden: false);
}

複製代碼

還可使用 meta 包下的 @required 註解來指定哪些參數是必須的:

void enableFlags({bool bold, @required bool hidden}) {}
複製代碼

可選的位置參數

語法格式:funcName(param1, param2, [opt1, opt2, …])

void enableFlags(bool bold, bool hidden, [bool underline]) {}

main() {
  enableFlags(false, false);
  enableFlags(false, false, true);
}

複製代碼

參數默認值

咱們可使用 = 爲可選參數提供默認值:

//可選參數
void enableFlags({bool bold = true, bool hidden = false}) {}

// dart 也容許使用 `:` 代替 `=`, 可是已經不建議使用
void enableFlags({bool bold : true, bool hidden : false}) {}

// 可選的位置參數
void enableFlags2([bool bold = true, bool hidden = false]) {}


複製代碼

須要注意的是參數的默認值必須是編譯時常量(runtime-constants):

void doStuff(
    {List<int> list = const [1, 2, 3],
    Map<String, String> gifts = const {
      'first': 'paper',
      'second': 'cotton',
      'third': 'leather'
    }}) {
  print('list: $list');
  print('gifts: $gifts');
}
複製代碼

函數做爲一等公民

函數做爲一等公民能夠將其做爲參數傳遞給另外一個函數,例如:

void printElement(int element) {
  print(element);
}

var list = [1, 2, 3];

// Pass printElement as a parameter.
list.forEach(printElement);
複製代碼

也能夠將函數賦值給一個變量:

void printMessage(String message) {
  print(message);
}

main() {
  var p = printMessage;
  p("assigning function to a variable");
}
複製代碼

匿名函數

匿名函數顧名思義就是沒有名字的函數, 能夠把沒有名字的函數稱之爲 匿名函數、lambda、閉包

匿名函數的語法格式:

([[Type] param1[, …]]) { 
  codeBlock; 
}; 
複製代碼

例以下面一個使用匿名函數的案例:

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

forEach 函數式這樣的定義的:

void forEach(void f(E element)){
    //...
}
複製代碼

而後咱們傳遞了一個匿名函數給 forEach 函數, 若是匿名函數體只有一條語句可使用箭頭函數簡化:

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

複製代碼

做用域

1. Lexical scope

Lexical scope 也稱之爲 靜態做用域(Static Scope), 也就是說變量的做用域是靜態肯定的

外部不能訪問內部做用域的變量, 可是內部做用域能夠訪問外部做用域的變量

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);
    }
  }
}
複製代碼

相對地, 有 Static Scope 就有 Dynamic Scope , 動態做用域就是說變量的做用域是動態肯定的

void fun(){
    printf("%d", x);
}

void dummy1(){
    int x = 5;
    fun();
}
複製代碼

例如上面的代碼, 在 fun 函數中並無定義 x 變量, 該變量在 dummy1 函數中定義了, dummy1 函數調用了 fun 函數, 因此 fun 函數中使用的 x 變量就是 dummy1 函數的中 x

2. Lexical closures

closures 能夠理解爲一個匿名函數, 它能夠訪問它本身的做用域內的變量, 哪怕變量已經超過了外部函數的做用域

例以下面的一個例子:

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

void 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);
}
複製代碼

上面的 makeAdder 函數返回一個匿名函數, 該匿名函數體內使用到了外部函數的變量 addBy

makeAdder 函數調用完畢後, 匿名函數依然可使用 addBy 變量.

Reference

關於 Dart 函數就講到這裏, 更多的關於 Android 學習資料能夠查看個人GitHub:

github.com/chiclaim/An…

stackoverflow.com/questions/1… dart.dev/guides/lang…


聯繫我

下面是個人公衆號,乾貨文章不錯過,有須要的能夠關注下,有任何問題能夠聯繫我:

公衆號:  chiclaim
相關文章
相關標籤/搜索