Java, PHP習得者がDartを学ぶ 5

スマホアプリ開発を夢見てFlutter/Dartの勉強を真剣にはじめてみたバックエンドエンジニア歴十数年の筆者が躓いた点やプログラミングに関してあらためて理解を深めたこと、などを記した備忘録です。

finalとconst

Dartの定数についてのお話です。ある変数の値を変更できないようにしたいときは、修飾子finalまたはconstを使用します。
この2つは値を変更できないということで似ているのですが、以下のような違いがあります。

  • const:コンパイル時定数であることを示す
  • final:再代入ができない変数であることを示す

詳しくは以降で説明しますが、同じような意味の修飾子でも性質が異なるため、正しく使い分ける必要があります。

const

constで宣言された定数は、コンパイルした時点で定数化されます。実行時に値を変更することができず、宣言時にのみ値の代入が可能です。
それではサンプルプログラムで挙動を見ていきましょう。

実行時に値を変更することができない。

void main() {
    const int x = 10;
    print("x = $x");

    // 以下はコンパイルエラー
    x = 100; // Constant variables can't be assigned a value.
}

const定数は宣言時にのみ値の代入が可能である。

void main() {
    // 以下はコンパイルエラー
    const int x; // The constant 'x' must be initialized.
    x = 10; // Constant variables can't be assigned a value.
}

final

finalは再代入ができない変数であることを示すための修飾子であり、final変数はプログラム実行時の初期化処理で値が決まります。
コンパイル時定数との挙動の違いをサンプルプログラムで見ていきましょう。

値を代入できるのは一回だけである。

void main() {
    final int x = 10;
    print("x = $x");

    // 以下はコンパイルエラー
    x = 100; // The final variable 'x' can only be set once.
}

変数だけ定義しておいて、後で値を代入することも可能である。

void main() {
    final int x;
    x = 10;
    print("x = $x"); // x = 10
}
void main() {
    final int x;
    x = 10;
    print("x = $x");
  
    // 以下はコンパイルエラー
    x = 100;
    print("x = $x"); // The final variable 'x' can only be set once.
}

クラスの定数フィールド

クラスで値を変更する必要のないフィールドを定義する場合もconst,finalを使い分ける必要があります。

finalフィールド

コンストラクタでフィールドの値を設定する場合はfinalを使用します。
なぜならconstを使用する場合、フィールド宣言時に値を設定する必要があり、コンストラクタでフィールドの値を設定するということができないためです。

class Member {
    final int _id;
    final String _name;

    Member(this._id, this._name);
  
    void printMember() {
        print("id:$_id name:$_name");
    }
}

void main() {
    Member m = Member(123, "suzuki");
    m.printMember(); // id:123 name:suzuki
}

ちなみに対象クラスのフィールドが全てfinalであり、コンストラクタにconstキーワードが付いている場合、constコンストラクタになります。

class Member {
    final int _id;
    final String _name;

    const Member(this._id, this._name);
  
    void printMember() {
        print("id:$_id name:$_name");
    }
}

void main() {
    Member m = const Member(123, "suzuki");
    m.printMember(); // id:123 name:suzuki
}

constフィールド

宣言時に値を代入する形でconstを使用することができます。その場合、staticを付けてクラス定数とする必要があります。また、クラス定数なのでインスタンス間で共有されます。

class Member {
    final int _id;
    final String _name;
    static const String country = "Japan";

    Member(this._id, this._name);
  
    void printMember() {
        print("id:$_id name:$_name cuntory:$country");
    }
}

void main() {
    Member m1 = Member(123, "suzuki");    
    Member m2 = Member(124, "sato");
    m1.printMember(); // id:123 name:suzuki cuntory:Japan
    m2.printMember(); // id:124 name:sato cuntory:Japan
}

※サンプルコードは「Flutter 3.7.11 Dart SDK 2.19.6」で実行しました。