Chapter 07

  関数、クラスの定義

heyhey1028
heyhey1028
2023.02.17に更新

関数定義

関数の定義は以下ルールに則ります。

  • 返り値の型 関数名(引数の型 引数名){処理 return 返り値;}
// ex. int型の引数を受け取り、String型の値を返す関数
String myFunction(int number){
    return number.toString();
}

返り値がない場合、返り値の型はvoid型となり、ブロック内では返り値を書かずreturn;で処理を終了します。

引数がない場合は()内を空欄になります。

void sayHello(){
    print('Hello World!!');
    return;
}

また=>を使ったアロー構文にも対応しています

void sayHello() => print('Hello World!!');

呼び出し

他の関数内で関数を呼び出す場合は関数名(引数);で呼び出します。末尾のセミコロンも忘れずに。

void main(){
    sayHello();
    final number = myFunction(52);
}

非同期関数

API 通信など非同期な処理を行う関数では返り値がFutureというデータ型になります。

// ex. APIを呼び出し、レスポンスを受け取るまで処理を待つ関数
Future<String> callApiFunction(int countryCode) async {
    return await getWeatherFromAPI(countryCode);
}

Future<>に返り値のデータ型を定義し、async/awaitキーワードで完了を待機する処理を定義します。

呼び出し

非同期関数の呼び出しでは呼び出し元の関数も非同期関数である必要があります。

Future<void> main() async {
    final weather = await callApiFunction(81);
}

名前付き引数

引数を{}で囲う事で名前付き引数を受け取る関数を定義する事ができます。その際にはその引数が必須か必須でないかを判断する必要があります。

もしその名前付き引数が必須であればrequiredという接頭辞を、もしその引数が必須でなければ、先にも紹介したnullを許容する型として定義する必要があります。

// 引数が必須の関数
String mySecondFunction({required int age}){
    return age.toString();
}

// 引数が必須ではない関数
void myThirdFunction({int? age}){
    print(age);
    print('Age might be null');
}

呼び出し

void main(){
   final String result = mySecondFunction(age:18);
}

クラス定義

クラスはオブジェクト指向プログラミングの核ともなるデータの集合体です。

オブジェクト指向プログラミングについては本題とずれてしまう為、深くは触れませんが、Flutter ではWidgetと呼ばれるクラスを駆使して UI を構築していくのでサラッと定義部分だけご紹介します。

class MyClass {
  // フィールド
  int _a;
  String _b;

  // ゲッター
  int get a => _a;
  String get b => _b;

  // セッター
  set a(int value) => _a = value;
  set b(String value) => _b = value;

  // コンストラクタ 
  // 引数がそのままフィールドに代入される
  MyClass(this._a, this._b);

  // Factoryコンストラクタ
  factory MyClass.fromJson(Map<String, dynamic> json) {
    return MyClass(json['a'], json['b']);
  }

  // メソッド
  void printValues() {
    print('a = $_a, b = $_b');
  }

  // staticメンバ
  static int myInt = 20;
  static void myFunc() {
    print('static var is $myInt');
  }
}

呼び出し(インスタンス化)

void main(){

    final MyClass myClass = MyClass(10, 'hello');

    print(myClass.a); // output: 10
    print(myClass.b); // output: hello
    myClass.printValues(); // output:a = 10, b = hello

    print(MyClass.myInt); // output: 20
    MyClass.myFunc(); // output: static var is 20
}

いくつかポイントとなる部分について解説していきます

_(アンダースコア)でプライベート変数化

クラス定義に限りませんが Dart では変数、関数、クラスの名前に _(アンダースコア)の接頭辞を付ける事で同一ファイル内でのみアクセス可能なプライベート変数にする事が出来ます。

my_fuctions.dart
void myGlobalFunction(){
    print('This is global');
}

void _myPrivateFunction(){
    print('This is private');
}

void myFunction(){
        myGlobalFunction(); // OK
        _myPrivateFunction(); // OK:同一ファイル内の為アクセス可能
}
main.dart
void main(){
    myGlobalFunction(); // OK
    _myPrivateFunction(); // NG:コンパイルエラーが発生します
}

本項のクラス定義ではフィールドをプライベート変数化する事でゲッターを通してのみアクセスできる様にしています。

コンストラクタの名前付き引数

関数の引数と同様でコンストラクタの引数を{}で囲う事で名前付き引数を取る事が出来ます。

関数の際と同様に必須か必須でないかに応じてrequiredを付けるか、?を付けて変数をオプショナルにする必要があります。

また名前付き引数を使う場合はプライベート変数に代入する事はできません。

class MyClass {
  // フィールド
  int a; // 必須
  String? b; // オプショナル

  // コンストラクタ 
  MyClass({required this.a, this.b});
}

void main(){
    // 必須なフィールドのみの代入でインスタンス化可能
    final MyClass myClass = MyClass(a: 10);
}

Factory コンストラクタ

flutter ではfactoryキーワードを用いたコンストラクタが用意されており、インスタンス化の際に複雑な処理を施したい場合に利用します。

下記のようにメソッド名を繋げて定義する事ができ、自由に引数を受け取り、処理を施した上でインスタンスを返す事ができます。

API から取得した Json データをモデルクラスに変換する際によく利用するため、覚えておくと便利です。

  // Factoryコンストラクタ
  factory MyClass.fromJson(Map<String, dynamic> json) {
    return MyClass(json['a'], json['b']);
  }

staticキーワードで静的メンバに

クラス自体に関連づけられた静的メンバを定義する際は変数の接頭辞にstaticキーワードを用います。

これらのメンバは下記のように、インスタンスではなく、クラス自体を通してのみアクセスする事が出来ます。

void main(){
    print(MyClass.myInt); // output: 20
    MyClass.myFunc(); // output: static var is 20
}

まとめ

簡単ではありますが、関数定義とクラス定義について解説しました。

Dart は Java や C# といったオブジェクト指向言語と比べると、関数定義やクラス定義の記法がシンプルである為、初学者にとっては覚えやすい言語だと思います。

また Flutter ではWidgetというクラスを使って構築していく為、クラス定義について最低限は理解しておきましょう。