iT邦幫忙

0

Dart 語言入門 2: 函式 Function

Functions 函數(方法)

在Dart語言,函數是物件也是一種叫做Function的型態(type)。因此,Function可以當成變數,也可以當做其他函數的參數;另外亦可把類別(class)的實體(instance)當做函數來呼叫。
建議為每個函數的參數以及回傳值都指定類型。

定義

//定義一個函數 判斷清單對應參數是否為null
bool isNoble(int atomicNumber) {
return list[atomicNumber] != null;
}

對於只有一個表達式的方法,可以選擇使用縮寫語法來定義

//定義一個函數 判斷清單對應參數是否為null 縮寫寫法
bool isNoble(int atomicNumber) => list[atomicNumber] != null;

=> 胖箭頭: 簡寫語法用於僅包含一句表達式的函數。這個語法特別是在將匿名函數作為參數傳遞時非常有用。
且在 => 與 ; 之間的只能是表達式,而非語句。例如你不能將一個 if語句 放在其中,但是可以放置條件表達式(condition ? expr1 : expr2)。

參數

有兩種類型的參數:必需和可選的。
必需的參數在參數列表前面,可選參數則是放置於必需參數的後面。

可選參數

可選參數分為命名參數和位置參數,可在參數列表中任選其一使用,但兩者不能同時出現在參數列表中。

命名參數

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

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

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

enableFlags(bold: true, hidden: false);

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

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

如果想要使用 Scrollbar 的建構式產生一個 Scrollbar 物件而不提供 child 這個參數,則會導致編譯錯誤。
@required 註解定義在 meta 套件中,可以直接導入 package:meta/meta.dart 使用。

位置参数

使用 [] 將一系列參數包裹起來作為位置參數:

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

下面是不使用可選參數呼叫say函數的例子

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

下面是使用可選參數呼叫say函數的例子

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

預設參數值

可以用 = 為函數的命名和位置參數定義預設值,預設值必須為編譯時常量,沒有指定預設值的情況下預設值為 null。

void main() {
  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 同樣也可以作為預設值。下面的範例定義了一個 doStuff() 的函數,其中的參數 list 和 gifts 指定了一個 List 類型的值和 Map 類型的值。

void main() {
  var list1 = [4,5,6];
  var map1 = {'first':'one','second':'two','third':'three'};
  
  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');
  }
  doStuff();
  doStuff(list:list1,gifts: map1);
}

https://ithelp.ithome.com.tw/upload/images/20200830/20121852LW2qiM8i0O.png

綜合範例

引用 IT人

//num a, num b, num c, num d 最普通的傳參: 呼叫時,引數個數和引數順序必須固定
add1(num a, num b, num c, num d) {
  print(a + b + c + d);
}

//[num a, num b, num c, num d]傳參: 呼叫時,引數個數不固定,但是引數順序需要一一對應, 不支援命名引數
add2([num a, num b, num c, num d]) {
  print(a + b + c + d);
}

//{num a, num b, num c, num d}傳參: 呼叫時,引數個數不固定,引數順序也可以不固定,支援命名引數,也叫可選引數,是dart中的一大特性,這就是為啥Flutter程式碼那麼多可選屬性,大量使用可選引數
add3({num a, num b, num c, num d}) {
  print(a + b + c + d);
}

//num a, num b, {num c, num d}傳參: 呼叫時,a,b引數個數固定順序固定,c,d引數個數和順序也可以不固定
add4(num a, num b, {num c, num d}) {
  print(a + b + c + d);
}

main() {
  add1(100, 100, 100, 100); //最普通的傳參: 呼叫時,引數個數和引數順序必須固定
  add2(100, 100); //呼叫時,引數個數不固定,但是引數順序需要一一對應, 不支援命名引數(也就意味著順序不變)
  add3(
      b: 200,
      a: 200,
      c: 100,
      d: 100); //呼叫時,引數個數不固定,引數順序也可以不固定,支援命名引數(也就意味著順序可變)
  add4(100, 100, d: 100, c: 100); //呼叫時,a,b引數個數固定順序篤定,c,d引數個數和順序也可以不固定
}
add3({num a, num b, num c, num d = 100}) {//d就是預設值引數,給的預設值是100
   print(a + b + c + d);             //1200
}

main() {
    add3(b: 200, a: 100, c: 800);
}
main() {
  Function square = (a) {
    return a * a;
  };

  Function square2 = (a) {
    return a * a * a;
  };
  print(add(3, 4, square, square2));           //9+64=73
}

num add(num a, num b, [Function op, Function op2]) {
  //函式作為引數傳遞
  return op(a) + op2(b);
}

main() 函數

每個程式都必須有一個 main() 函數作為入口,main() 函數回傳值為 void 並且有一個 List <String> 類型的可選參數。

void main(List<String> arguments) {
  print(arguments);
  print(arguments.length);
  print(arguments[1]);
}

https://ithelp.ithome.com.tw/upload/images/20200830/201218528jhRhP2Tdw.png

匿名函數

沒有名字的函數,稱之為 匿名函數,或 Lambda表達式 或 Closure閉包。
你可以將一個變數設為匿名函數,然後使用它,亦可將該變數添加到集合或從中刪除。
匿名函數看起來與命名函數類似,在括號之間可以定義參數,參數之間用逗號分割;後面大括號中的內容則為函數體:
([[類型] 參數[, …]]) {
函數體;
};

void main() {
  var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
  print(loudify('hello'));            //!!! HELLO !!!
}
void main() {
  var list = ['apples', 'bananas', 'oranges'];
  list.forEach((item) {
    print('${list.indexOf(item)}: $item');    
  });
}

https://ithelp.ithome.com.tw/upload/images/20200830/20121852LSVQxJ6dRf.png

支援閉包(closure)

函數可以封閉定義到它範疇(scope)內的變數。接下來的範例中,函數 makeAdder() 設定了變數 addBy。無論函數在什麼時候return,它都可以使用設定的 addBy 變數。

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

void main() {
  // 生成加 2 的函数。
  var add2 = makeAdder(2);

  // 生成加 4 的函数。
  var add4 = makeAdder(4);

  print(add2(3));     //5
  print(add4(3));     //7
}

尚未有邦友留言

立即登入留言