iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 8
0

先前的範例都是將程式碼寫在 void main(){} 裡面,如果需要處理/運算的步驟很多,在 main() 中會出現很多程式碼,對於維護是相當不容易的,在實務上也不會這麼做。

一般來說,會根據每一個功能建立不同的類 (Class),而在每一個類裡面都有自己的函數。

所以外界需要將類實例化,接者才能呼叫函數。

函數 (Functions)

將程式碼定義在函數內,可以隱藏不必要的實作,外面呼叫時,只需要在意輸入的變數以及輸出的型態。

每一個函數都代表一個特定的任務,可能有回傳值,也有可能有副作用。

定義一個函數

void functionName(){
	print('This is function');
}

定義一個函數分為四個部分,

  1. 回傳類型
  2. 函數名稱
  3. 參數
  4. 函數本體

套用上方的範例:

  1. 回傳類型:void
  2. 函數名稱:functionName
  3. 參數:()無參數
  4. 函數本體:{print('This is function');}

回傳類型中的 void ,代表這個函數沒有回傳值,呼叫此函數會得到一個副作用(print)。

表達式 (Expression)

可以將上面的範例,以表達式改寫:

改寫方式:將函數本體的大括弧移除,並在前方加上箭頭 (=>)。

void functionName() => print('This is function');

若函數本體只有一行,用表達式可以縮減行數,僅用一行程式碼便看完本體。

函數若有回傳值,使用表達式則可以省略 return 關鍵字。

int function2(){
	return 10;
}

//用表達式改寫
int function2() => 10;

呼叫函數

定義完函數之後,我們該如何呼叫呢?

輸入函數的名稱加上括弧,則表示呼叫該函數。

void main(){
	function1();

	var result = function2();
	print(result);
}

void functionName() => print('This is function');
int function2() => 10;

好der,我們已經學習如何定義一個函數,並且可以改寫成表達式,但是上面範例中,都沒有任何輸入的參數。

接下來,我將繼續介紹如何定義帶入的參數。

函數的參數

Dart 中,函數有兩種呼叫函數帶入參數的方式,一種是用名稱指定,一種是根據位置帶入。

位置參數 (Positional parameter)

void printIt(String name, int age){
	print("My name is $name, I'm $age.");
}

我們知道,在函數名稱後面的括弧內是定義參數的地方。

參數定義:[Type] [name],並用逗號分隔。

由此得知上面範例,我們定義了兩個參數:

  1. String name
  2. int age

呼叫的時候,就必須要根據參數定義的順序、數量,來逐一傳入,如下

void main(){
	printIt('Leo', 30);
}
//My name is Leo, I'm 30

如果順序錯誤,會發生編譯期錯誤。

printIt(30, 'Leo'); //Compilation-error

非必要參數

定義函數時,可以將非必要參數使用中括弧包起來,呼叫函數時,就不一定需要帶入此參數。

void printIt(String name, int age, [String greeting]){
  greeting ??= "Hello";
  print("$greeting, My name is $name, I'm $age.");
}
void main(){
	printIt('Andy', 35, 'Hey');
	printIt('Jason', 40);
}
// Hey, My name is Andy, I'm 35.
// Hello, My name is Jason, I'm 40.

我們可以替非必要參數加上預設值。

  • 加上預設值的方法:在變數名稱後方用等於指定預設值。
void printIt(String name, int age, [String greeting = "Hello"]){
  print("$greeting, My name is $name, I'm $age.");
}

命名參數 (Named Parameter)

呼叫函數時,有時候會不清楚輸入的參數是什麼,必須要移動到函數定義查看。

在定義參數時,我們用大括弧將參數包起來。當呼叫函數時,就必須使用名稱來帶入參數,不需要根據其定義的順序。

在呼叫的時候,就可以清楚地知道帶入的參數是什麼用途。

void main(){
	printIt(name:'Leo', age:30);
}
void printIt({String name, int age}){
	print("My name is $name, I'm $age.");
}
  • 用大括弧定義參數,表示這些參數是可選的,不一定需要輸入,呼叫時,可以省略該參數。

但是,我們有時候是需要命名參數這項功能,不是要讓該參數成為可省略的,我們可以在參數前方加上註解 @required

@required

在參數前方加上 @required ,當呼叫函數卻未帶入該參數時,編譯器會出現警告,如此,就可以避免忘記傳值的情況。

void printIt({@required String name, @required int age}){
	print("My name is $name, I'm $age.");
}

加上預設值

我們亦可以在變數後方加上等號指定預設值。

void printIt({ @required String name = "Andy", @required int age = 30 }){
	print("My name is $name, I'm $age.");
}

型別推斷

函數,同樣也支援型別推斷,無論是回傳值的型別,或是輸入參數的型別,都可以使用型別推斷,但是使用型別推斷可能會讓函數的可讀性變差,使用時要注意。

printIt(name, age){
	print("My name is $name, I'm $age.")
}

小結

函數是程式裡最基本的項目之一,Dart 提供了多種方式傳入參數,如果一個函數只有一個參數,使用位置參數是最合適的,如果有多個參數,可以考慮使用命名參數。那麼,在呼叫函數的時候,
才不會不同檔案切來切去,造成不便。

在使用命名參數時,@required 註解我認為是必要加入的,因為採用命名參數時,這些參數都不是強制輸入,若使用函數的人少傳了一個參數,有可能會造成非預期的動作。加上 @required 可以在使用該函數時減少這類的情況發生。


上一篇
Day7:內建型態(集合) - Maps
下一篇
Day9:匿名函數(Anonymous function)
系列文
Dart 語言 - 開啟 Flutter 的鑰匙30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言