アプリエンジニアが教えるわかりやすいDart入門(2)関数

Dart_programming_language_logo

関数

前回の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;を代入しています。

実際には仮引数addBy2が渡されるので、(int i) => 2 + i;となります。

この時点ではmakeAdder()関数は実行されません。

この後、add2(3)を実行すると仮引数i3が渡されるので(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

次回は演算子について投稿する予定です。

たかひら かずま
ウォーキングをしながら音楽を聴いたり考えごとをするのが好きです。
最近リモートワークで太ってしまったのでダイエットに挑戦中!

Egg Device Application

東京品川のスマホアプリ製作・開発会社です。
一般アプリ業務用アプリからVRアプリまで開発可能。

求人情報

スマホアプリ製作・開発の
相談を受け付けています

メールでのご相談

お電話でのご相談
TEL 03-5422-7524
平日10:00~18:00