対象読者
Dart言語について特に知っている必要はありませんが、他の言語の基本を知っている方を対象に説明いたします。特に、JavaScriptやTypeScriptもしくは、Javaなど言語を使ってプログラミングしたことがある方であれば、より理解がしやすくなります。
関数について
Flutterでよく見る関数の使い方で名前付き引数があります。名前付き引数を採用している言語にはC#やSwiftなどがあります。また、JavaScriptやTypeScriptでは、言語レベルでの名前付き引数はサポートしていませんが、同じような効果を得るためにオブジェクトの分割代入の仕組みを使っているコードを見るようになりました。
名前付き引数はコードが見にくくなるといった意見もありますが、使う用途によっては良い面もあり、名前付き引数のメリットを表している一例としてリスト1のコードがあります。
build( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, ), ) );
このコードは計算するための関数ではなく、定義または設定のためのコードです。Dartは主にUIを扱うための言語であるため、UI構造を設定するようなコードを記述する必要があります。そのため少々冗長になってしまいますが、このようなコードのほうが見通しは良くなります。
このように、UIを扱いやすいためにできている言語であることを前提として見ていただくと、Dartの少々わかりにくいと感じる部分でも、実際に使って見ると使いやすいと感じるはずです。
関数定義
続いて、基本的な関数の定義について紹介します。リスト2は関数の定義方法です。
<戻り値の型> <関数名>([<引数の型> <引数値>],[<引数の指定>]){ return <戻り値>; }
この定義に沿って作った簡単な関数がリスト3です。
// (1)定義に沿った関数例 String helloWorld1(String world){ return 'Hello $world'; } // (2)戻り値と引数の型定義を省略 helloWorld2(world){ return 'Hello $world'; } // (3) 1行関数での記述例 String helloWorld4(String world) => 'Hello $world'; // (4)戻り値がいらない場合 void helloWorld3(){ print('Hello'); }
(1)は他の言語とも違わない、標準的な関数の実装例です。そして(2)のように戻り値と引数の型を省略することも可能です。省略した場合の型はdynamicとして扱われます。そのため、厳密には(1)と同じではありません。
(3)は、(1)と同じことを1行関数で書き直したものです。その場合はシグニチャと本体とを「=>」でつなぎます。(4)はreturn文を省略したものです。戻り値がない場合には、戻り値の型にvoidを指定します。戻り値の型を省略した場合には、先ほどと同様にdynamicとして扱われ、その場合にはnullが戻り値となります。
引数の指定方法は、先ほど紹介した名前付き引数以外にもいくつか指定方法があるので、それらの使い方を紹介します。
名前付き引数
Flutterのコードではよく見る引数の指定方法で、名前付き引数では"{}"内に定義する必要があります。リスト4は名前付き引数を使った場合のコード例です。
// (1)引数の定義例 computeSum({ int val1 , int val2}){ return val1 + val2; } void main(){ computeSum( val1 : 3, val2 :5 ); // (2)使い方 computeSum( val1 : 5); // (3)省略が可能 }
(1)の通り引数を定義すると、(2)のようにそれぞれの引数を指定することが可能です。また、指定する引数の順番は関係ありません。また、(3)の通りに引数を省略することも可能です。省略するとnullが設定されてしまうので、実装側で制御しないと正しく動かなくなります。そこで、リスト5のような省略された場合のデフォルト値の設定や、入力を必須にする方法があります。
import 'package:meta/meta.dart'; // (1) 通常形式の引数と名前付き引数の混在 computeSum1(int val1 , { int val2 }){ } // (2) 省略されたときのデフォルト値の指定 computeSum2({ int val1 = 0, int val2 = 0 }){ } // (3) 省略されないようにするためのアノテーション指定 computeSum3({ @required int val1, int val2 = 0 }){ }
(1)は、通常引数と名前付き引数を混合させる場合の例です。必ず指定する必要がある引数は、通常引数として定義し、オプションとなる引数を名前付き引数で指定します。
このように混合させる場合には、通常引数の定義後に、名前付き引数を指定してください。そして、省略されたときのデフォルト値を指定する場合には、(2)のように=(イコール)で値を指定できます。
また、デフォルト値が指定できず、名前付き引数を利用したい場合には、(3)のように@requiredというアノテーションを利用します。ただし、このアノテーションはDartの基本ライブラリだけでは利用できないので、'package:meta/meta.dart'をインポートする必要があります。Flutterプロジェクトであれば、別途、インポートする必要はありません。
オプショナル引数
オプショナル引数は、通常引数の指定方法と同じですが、引数を省略できるようにした指定方法です。オプションとして指定する引数は、[]内に定義します。リスト6は、カンマ区切りの文字列をリスト形式に変換するような関数を想定した場合のコード例です。
// (1)引数の指定 ListsplitString(String input , [ String split = ',' , int max = 100 ]){ // 省略 } main(){ // (2)実際の利用例 splitString("data1,data2,data3"); splitString("data1-data2-data3","-"); // 区切り文字を"-"に変更 splitString("data1,data2,data3,data4",",",3); // 最大の100から3に変更 }
(1)のように、必須となる引数はオプショナル引数の前に必ず指定します。=(イコール)を使って省略された場合の値を指定します。指定しない場合にはnullが設定されます。そして、実際に利用する場合は(2)の通りに利用します。オプショナルと指定した部分の順番は変更できません。また、途中だけ省略するといったこともできません。