天天看點

Functions——Dart

Functions——Dart

Dart是一個完全面向對象的語言,它的方法也是對象,對應的類型為Function。

這意味着方法也能被指派給變量,或者當做參數傳遞給其他方法。

下面是一個方法的的示例:

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

函數參數

  • 可選命名參數
  • 可選位置參數
  • 參數預設值

具體請看Functions Paramaters——Dart

main()方法

每個app都必須有一個頂級的main()方法來作為app的入口。main()方法的傳回值為

void

類型,方法參數為

List<String>

的可選參數。

下面的main方法可以接受指令行攜帶過來的參數:

// 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

函數作為一等公民

函數可以作為參數傳遞給另一個函數。

例如:

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

main(){
  var list = [1, 2, 3];

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

output:
1
2
3
           
将函數指派給一個變量
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');
           

這裡使用了匿名方法。

匿名方法

大多數方法都會被命名,比如說

main()

printElement()

。你也可以建立沒有名字的方法,我們稱之為匿名函數;還可以建立lambda表達式或者閉包。

你也可以将匿名函數指派給一本變量,例如你将這個變量從集合中添加或者移除。

匿名方法的參數跟正常方法類似——0或多個參數,由逗号分隔,可選的類型注解,在一對圓括号内部。

下面的代碼塊包含了方法體:

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

下面的示例定義了一個包含無類型參數item的匿名方法。這個方法被list中的每個item調用,會根據角标擷取item的值,然後列印出對應的String。

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

output:
0: apples
1: bananas
2: oranges
           
使用箭頭表達式簡寫

如果匿名方法的方法體中隻包含一行表達式,這時可以使用箭頭表達式來簡化。

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

output:
0: apples
1: bananas
2: oranges
           

Lexical scope——作用域

Dart語言支援作用域,這意味着變量的作用域是由代碼所處的位置靜态決定的。

你可以根據方法體的花括号來判斷變量是否在作用域内部。

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方法可以調用外部各個層級的變量,包括頂級的成員變量。

Lexical closures——閉包

閉包是一個可以通路自己的作用域變量的函數對象,甚至閉包當原始作用域的外部使用時也可以。

閉包的概念參考學習Javascript閉包(Closure)——阮一峰

在下面例子中,

makeAdder()

方法捕獲了變量

addBy

,不管傳回的方法如何,它已經記錄下了

addBy

/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(num addBy){
  abc(num i){
    return addBy + i;
  }
  return abc;
}

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(num addBy){
  abc(num i){
    return addBy + i;
  }
  return abc;
}
           

内部方法可以使用匿名方法代替:

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

當然,方法的傳回值也可以省略

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

測試方法的一緻性

下面這個例子測試了頂級方法、靜态方法和執行個體方法的一緻性。

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);// true

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

  // 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);// true

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

傳回值

所有非void方法都有傳回值。如果沒有指定傳回值,則方法體的末尾會隐式地添加一句

return null;

foo() {}

void baz() {}

main() {
  assert(foo() == null);
//  assert(baz() == null);// 編譯期異常
}
           

參考:

https://www.dartlang.org/guides/language/language-tour#functions