Dart(2.2) - 函數(shù)(Functions)

函數(shù)(Functions)

Dart是一個(gè)真正的面向?qū)ο笳Z(yǔ)言,方法也是對(duì)象并且具有一種類型 Function。 這意味著,方法可以賦值給變量,也可以當(dāng)做其他方法的參數(shù)。 也可以把Dart類的實(shí)例當(dāng)做方法來(lái)調(diào)用。 詳情請(qǐng)參考Callable classes.

下面是定義方法的示例:

bool isNoble(int atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}

雖然在Effective Dart中推薦type annotations for public APIs, 你當(dāng)然也可以選擇忽略類型定義:

isNoble(atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}

對(duì)于只有一個(gè)表達(dá)式的方法,你可以選擇使用縮寫(xiě)語(yǔ)法來(lái)定義:

bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;

這個(gè) => expr 語(yǔ)法是 { return expr; }形式的縮寫(xiě)。=>形式有時(shí)候也稱之為箭頭語(yǔ)法。

注意: 在箭頭 (=>)和分號(hào)(;)之間只能使用一個(gè)表達(dá)式 – 不能使用語(yǔ)句。 例如:你不能使用 if statement,但是可以使用條件表達(dá)式conditional expression.

方法可以有兩種類型的參數(shù):必需的(required)和可選的(optional)。 必需的參數(shù)在參數(shù)列表前面, 后面是可選參數(shù)。被命名為可選的參數(shù)也能被標(biāo)記為@required。

可選參數(shù)(Optional parameters)

可選參數(shù)可以是命名參數(shù)或者基于位置的參數(shù),但是這兩種參數(shù)不能同時(shí)當(dāng)做可選參數(shù)。

可選命名參數(shù)(Optional named parameters)

調(diào)用方法的時(shí)候,你可以使用這種形式 paramName: value 來(lái)指定命名參數(shù)。例如:

enableFlags(bold: true, hidden: false);

在定義方法的時(shí)候,使用 {param1, param2, …}的形式來(lái)指定命名參數(shù):

/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold, bool hidden}) {...}

Flutter實(shí)例創(chuàng)建表達(dá)式能夠變得非常復(fù)雜,所以widget的構(gòu)造器使用了命名參數(shù),這樣創(chuàng)建實(shí)例易于閱讀。

我們也可以在任意的Dart代碼中使用命名參數(shù),使用@required表示該參數(shù)是必須的。

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

當(dāng)Scrollbar被創(chuàng)建的時(shí)候,如果child參數(shù)缺少將會(huì)報(bào)錯(cuò)。Required是被定義在meta package中。所以要么直接倒入package:meta/meta.dart,或者其他package中有倒入meta,比如:Flutterpackage:flutter/material.dart.

可選位置參數(shù)(Optional positional parameters)

把一些方法的參數(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;
}

下面是不使用可選參數(shù)調(diào)用上面方法 的示例:

assert(say('Bob', 'Howdy') == 'Bob says Howdy');

下面是使用第三個(gè)可選參數(shù)調(diào)用上面方法的示例:

assert(say('Bob', 'Howdy', 'smoke signal') ==
    'Bob says Howdy with a smoke signal');

默認(rèn)參數(shù)值(Default parameter values)

在定義方法的時(shí)候,可以使用=為命名和位置參數(shù)來(lái)定義默認(rèn)值。 默認(rèn)值必須是編譯時(shí)常量。 如果沒(méi)有提供默認(rèn)值,則默認(rèn)值為null。

下面是為命名參數(shù)設(shè)置默認(rèn)值的示例:

/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold = false, bool hidden = false}) {...}

// bold will be true; hidden will be false.
enableFlags(bold: true);

版本問(wèn)題: 老版本代碼可能需要使用一個(gè)冒號(hào) (:) 而不是 = 來(lái)設(shè)置參數(shù)默認(rèn)值。 : 設(shè)置命名默認(rèn)參數(shù)值在以后版本中將不能使用, 所以推薦你 **使用 = 來(lái)設(shè)置默認(rèn)值

下面的示例顯示了如何設(shè)置位置參數(shù)的默認(rèn)值:

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

assert(say('Bob', 'Howdy') ==
    'Bob says Howdy with a carrier pigeon');

還可以使用list或者map作為默認(rèn)值。 下面的示例定義了一個(gè)方法 doStuff(), 并分別為listgifts參數(shù)指定了 默認(rèn)值。

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');
}

入口函數(shù)(The main() function)

每個(gè)應(yīng)用都需要有個(gè)頂級(jí)的main()入口方法才能執(zhí)行。 main()方法的返回值為void并且有個(gè)可選的List<String>參數(shù)。

下面是一個(gè)web應(yīng)用的main()方法:

void main() {
  querySelector('#sample_text_id')
    ..text = 'Click me!'
    ..onClick.listen(reverseText);
}

注意: 前面代碼中的 .. 語(yǔ)法為cascade.。 使用級(jí)聯(lián)調(diào)用語(yǔ)法, 你可以在一個(gè)對(duì)象上執(zhí)行多個(gè)操作。

下面是一個(gè)命令行應(yīng)用的main()方法,并且使用了方法參數(shù)作為輸入?yún)?shù):

// Run the app like this: dart args.dart 1 test
void main(List<String> arguments) {
  print(arguments);

  assert(arguments.length == 2);
  assert(int.parse(arguments[0]) == 1);
  assert(arguments[1] == 'test');
}

你可以使用args library來(lái)定義和解析命令行輸入的參數(shù)數(shù)據(jù)。

一等方法對(duì)象(Functions as first-class objects)

可以把方法當(dāng)做參數(shù)調(diào)用另外一個(gè)方法。例如:

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

var list = [1, 2, 3];

// Pass printElement as a parameter.
list.forEach(printElement);

方法也可以賦值給一個(gè)變量:

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

上面的方法為,下面將介紹的匿名方法。

匿名方法(Anonymous functions)

大部分方法都帶有名字,例如main()或者printElement()。 你有可以創(chuàng)建沒(méi)有名字的方法,稱之為匿名方法,有時(shí)候也被稱為lambda或者 closure閉包。 你可以把匿名方法賦值給一個(gè)變量,比如:添加到集合或者從集合中刪除。

匿名函數(shù)形式如下,大括號(hào)中的代碼為函數(shù)體:

([[Type] param1[, …]]) { 
  //codeBlock; 
}; 

下面的代碼定義了一個(gè)參數(shù)為item(該參數(shù)沒(méi)有指定類型)的匿名函數(shù)。list中的每個(gè)元素都會(huì)調(diào)用這個(gè)函數(shù)來(lái)打印出來(lái),同時(shí)來(lái)計(jì)算了每個(gè)元素在 list中的索引位置。

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

如果方法只包含一個(gè)語(yǔ)句,可以使用箭頭語(yǔ)法縮寫(xiě)

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

靜態(tài)作用域(Lexical scope)

Dart是靜態(tài)作用域語(yǔ)言,變量的作用域在寫(xiě)代碼的時(shí)候就確定過(guò)了。 基本上大括號(hào)里面定義的變量就只能在大括號(hào)里面訪問(wèn)

下面是嵌套函數(shù)顯示變量作用域的一個(gè)示例:

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() 可以訪問(wèn)所有的變量, 包含頂級(jí)變量。

詞法閉包(Lexical closures)

閉包是方法對(duì)象,不管該對(duì)象在何處被調(diào)用, 該對(duì)象都可以訪問(wèn)其作用域內(nèi)的變量。

方法可以封閉定義到其作用域內(nèi)的變量。 下面的示例中,makeAdder()捕獲到了變量 addBy。 不管你在那里執(zhí)行 makeAdder()所返回的函數(shù),都可以使用addBy參數(shù)。

/// Returns a function that adds [addBy] to the
/// function's argument.
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);
}

測(cè)試函數(shù)是否相等(Testing functions for equality)

下面是測(cè)試頂級(jí)方法、靜態(tài)函數(shù)和實(shí)例函數(shù) 相等的示例:

void foo() {} // A top-level function

class A {
  static void bar() {} // A static method
  void baz() {} // An instance method
}

void main() {
  var x;

  // Comparing top-level functions.
  x = foo;
  assert(foo == x);

  // Comparing static methods.
  x = A.bar;
  assert(A.bar == x);

  // Comparing instance methods.
  var v = A(); // Instance #1 of A
  var w = A(); // Instance #2 of A
  var y = w;
  x = w.baz;

  // These closures refer to the same instance (#2),
  // so they're equal.
  assert(y.baz == x);

  // These closures refer to different instances,
  // so they're unequal.
  assert(v.baz != w.baz);
}

返回值(Return values)

所有的函數(shù)都返回一個(gè)值。如果沒(méi)有指定返回值,則默認(rèn)把語(yǔ)句 return null; 作為函數(shù)的最后一個(gè)語(yǔ)句執(zhí)行。

foo() {}

assert(foo() == null);

參考

Dart

最后編輯于
?著作權(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ù)。

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