アプリ開発日誌
2021.07.16
Flutter開発のためのDart入門(2)関数
関数
前回のDart入門(1)の投稿に続き、今回もDartについて解説していきます。
今回は関数について解説します。
関数の定義
基本的な関数の定義は次のようになります。
戻り値の型 関数名 (仮引数の型 仮引数名) { return 戻り値; }
関数の呼び出しは次のようになります。
関数名 (実引数);
簡単な関数の実装例は次のようなコードになります。
String sayHello(String name) { return 'Hello ${name}'; } void main() { var greeting = sayHello('Satoshi'); print(greeting); }
実行結果
Hello Satoshi
式を1つだけ含む関数の場合は、return
の代わりにアロー演算子=>
を使い簡潔に記述できます。
String sayHello(String name) => 'Hello ${name}'; void main() { var greeting = sayHello('Satoshi'); print(greeting); }
実行結果
Hello Satoshi
関数のパラメータ
関数は任意の数のパラメータ(仮引数)を持つ事ができます。
仮引数が複数ある場合、カンマ,
で区切ります。
int area(int height, int width) { return height * width; } void main() { var result = area(2, 3); print(result); }
実行結果
6
名前付きパラメータ
関数を定義する際に仮引数を{}
で囲むと、呼び出し側で実引数に名前を付けられます。
戻り値の型 関数名 ({仮引数の型: 仮引数名}) { return 戻り値; }
関数の呼び出しは次のようになります。
関数名 (仮引数名: 実引数);
名前付きパラメータはオプションで省略可能のため、値がnull
になる可能性があります。
※Dart 2.12 以降で null-safe(null 安全)を選択した場合、仮引数の型名に?
クエスチョンマークを付けないとコンパイルエラーとなります。
下記のコードはnullチェックをif文でおこなっています。
if文は今後の投稿で解説します。
String say(String from, String msg, {String? device}) { var result = '$fromからのメッセージ 「$msg」'; if (device != null) { result = '$result 〜$deviceから'; } return result; } 実行結果 void main() { var message = say('タロー', '元気ですか?'); print(message); message = say('タロー', '元気ですか?', device: 'スマートフォン'); print(message); }
タローからのメッセージ 「元気ですか?」 タローからのメッセージ 「元気ですか?」 〜スマートフォンから
オプショナルパラメータ
仮引数を[]
で包むと、オプションのパラメータになります。
String say(String from, String msg, [String? device]) { var result = '$fromからのメッセージ 「$msg」'; if (device != null) { result = '$result 〜$deviceから'; } return result; } void main() { var message = say('タロー', '元気ですか?'); print(message); message = say('タロー', '元気ですか?', 'スマートフォン'); print(message); }
実行結果
タローからのメッセージ 「元気ですか?」 タローからのメッセージ 「元気ですか?」 〜スマートフォンから
名前付きパラメータは省略可能ですが、@required
というアノテーションを付けると、仮引数に値を指定するのが必須になります。
※@required
を使用するには下記のパッケージをインポートします。
import 'package:meta/meta.dart';
import 'package:meta/meta.dart'; String say({@required String? from, @required String? msg, String? device}) { var result = '$fromからのメッセージ 「$msg」'; if (device != null) { result = '$result 〜$deviceから'; } return result; } void main() { var message = say(from: 'タロー', msg: '元気ですか?', device: 'スマートフォン'); print(message); message = say(from: 'タロー', msg: '元気ですか?'); print(message); message = say(from: 'タロー'); // 引数'msg'を省略 print(message); }
実行結果
タローからのメッセージ 「元気ですか?」 〜スマートフォンから タローからのメッセージ 「元気ですか?」 タローからのメッセージ 「null」 // line 16 • The parameter 'msg' is required.
デフォルトパラメータ
=
を使用して、名前付きパラメータとオプショナルパラメータの両方のデフォルト値を定義することができます。
String say(String from, String msg, [String? device = 'スマートフォン']) { var result = '$fromからのメッセージ 「$msg」'; if (device != null) { result = '$result 〜$deviceから'; } return result; } void main() { var message = say('タロー', '元気ですか?'); print(message); }
実行結果
タローからのメッセージ 「元気ですか?」 〜スマートフォンから
main関数
main()関数は一つだけ存在できます。
main()
の前にあるvoid
は関数の戻り値の型です。
main()関数やprint()関数など、値を返さない関数の場合、この戻り値の型を指定します。
匿名関数
関数には関数名がありますが、関数名の無い関数もあります。
これを匿名関数(無名関数)と言います。
Dartでは関数を変数に代入したり、別の関数のパラメータとして渡すことができます。
無名関数の定義は次のようになります。
(仮引数の型 仮引数名) { return 戻り値; }
コードは次のようになります。
void main() { var greeting = (name) { return 'Hello, ${name}!'; }; print(greeting('Dart')); }
実行結果
Hello, Dart!
関数の型はFunction型です。
void main() { var greeting = (name) { return 'Hello, ${name}!'; }; print(greeting('Dart')); print(greeting is Function); }
実行結果
Hello, Dart! true
次のコードはパラメータitem
を持つ無名関数を定義しています。
この関数は、リスト内の各項目に対して呼び出され、指定されたインデックスの値を含む文字列を表示します。
void main() { var list = ['apples', 'bananas', 'oranges']; list.forEach((item) { print('${list.indexOf(item)}: $item'); }); }
実行結果
0: apples 1: bananas 2: oranges
スコープ
Dartはスコープ(可視範囲)が有効な言語です。
スコープとは、ある変数や関数などの名前(識別子)を参照できる範囲のことです。
通常、変数や関数が定義されたスコープの外側からは、それらの名前を用いるだけでは参照できません。
このときこれらの変数や関数は「スコープ外」である、あるいは「見えない」といわれます。
通例、入れ子になったスコープ階層ごとに同じ名前の識別子が出現したとき、より内側のスコープに属する識別子のほうが優先的に参照されます。
void main() { var x = 100; print(x); // 100 { var x = 200; print(x); // 200 var y = 300; } print(x); //100 // コメントを外すとコンパイルエラー // print(y); }
実行結果
100 200 100
静的クロージャ (Lexical closures)
クロージャはStringやintを変数に保存するように、関数オブジェクトとして保存します。
次のコードは変数add2
に、実引数に2
を渡したクロージャ(int i) => addBy + i;
を代入しています。
実際には仮引数addBy
に2
が渡されるので、(int i) => 2 + i;
となります。
この時点ではmakeAdder()
関数は実行されません。
この後、add2(3)
を実行すると仮引数i
に3
が渡されるので(int 3) => 2 + 3;
が実行されて5
になります。
この後、add4
変数にmakeAdder(4)
を代入しても、変数add2
にはmakeAdder(2)
が保持され続けます。
Function makeAdder(int addBy) { return (int i) => addBy + i; } void main() { var add2 = makeAdder(2); var add4 = makeAdder(4); print(add2(3) == 5); print(add4(3) == 7); }
実行結果
true true
次回は演算子について投稿する予定です。
ライタープロフィール
【N】
Webエンジニアの経験を経て、アプリエンジニアとしてEDAに入社。
Flutter開発導入のファシリテーターとして、勉強会などを担当している。