Menu
Coddy logo textTech

FinalとConstフィールド

CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 18/110。

クラスでフィールドを宣言する際、初期化後に値が変更可能かどうかを制御するために final または const を使用できます。どちらも不変の値を作成しますが、その仕組みは異なります。

final フィールドは一度しか設定できませんが、その値は実行時に決定されます。宣言時、またはコンストラクタを通じて割り当てることができます。

class Person {
  final String name;
  final DateTime createdAt = DateTime.now();
  
  Person(this.name);
}

Person p = Person('Alice');
// p.name = 'Bob';  // エラー: finalフィールドを再代入することはできません

name はオブジェクトの作成時に設定され、createdAt は現在の時刻をキャプチャします。初期化後、両方の値はロックされます。

static const フィールドは、コンパイル時に値が確定している必要があります。これはクラス自体に属し、すべてのインスタンス間で共有されます:

class Circle {
  static const double pi = 3.14159;
  final double radius;
  
  Circle(this.radius);
  
  double get area => Circle.pi * radius * radius;
}

主な違いは次のとおりです。final フィールドは実行時に計算された値(DateTime.now() など)を保持できますが、const はコンパイル時定数を必要とします。インスタンスフィールドを直接 const にすることはできません。クラスレベルでは static const のみが許可されます。

challenge icon

チャレンジ

簡単

final フィールドと static const フィールドの違いを実演する商品カタログシステムを構築しましょう。不変(immutable)なプロパティと共有の構成値を持つ商品を作成します。

コードを2つのファイルに整理します:

  • product.dart: 店舗のアイテムを表す Product クラスを定義します。クラスには以下のものを含めてください:
    • すべての商品で共有される static const double taxRate0.08 (8%の税率)に設定
    • static const String currency'USD' に設定
    • 商品の名前のための final String name (コンストラクタ経由で設定)
    • 商品の基本価格のための final double basePrice (コンストラクタ経由で設定)
    • プレフィックスと商品名を組み合わせた final String sku (stock keeping unit)。初期化リストで 'SKU-' の後に大文字の名前を続けて計算します
    • namebasePrice を受け取るコンストラクタ
    • 税込み価格を計算するゲッター priceWithTax
    • 商品情報を表示する display() メソッド
  • main.dart: 商品クラスをインポートし、2つの商品を作成します:
    • 基本価格 999.99'Laptop'
    • 基本価格 29.99'Mouse'
    上記でリストされた順序で、各商品に対して display() を呼び出します。

display() メソッドは、以下の正確な形式で出力する必要があります:

[sku] - [name]: [basePrice] [currency] (with tax: [priceWithTax] [currency])

表示する際、priceWithTaxtoStringAsFixed(2) を使用して小数点以下2桁に丸めてください。

期待される出力:

SKU-LAPTOP - Laptop: 999.99 USD (with tax: 1079.99 USD)
SKU-MOUSE - Mouse: 29.99 USD (with tax: 32.39 USD)

チートシート

実行時に一度だけ設定され、その後変更できないフィールドには final を使用します。クラスのすべてのインスタンスで共有されるコンパイル時定数には static const を使用します。

final フィールドは実行時に設定され、宣言時またはコンストラクタで初期化できます:

class Person {
  final String name;
  final DateTime createdAt = DateTime.now();
  
  Person(this.name);
}

static const フィールドは、コンパイル時定数である必要があり、クラス自体に属します:

class Circle {
  static const double pi = 3.14159;
  final double radius;
  
  Circle(this.radius);
  
  double get area => Circle.pi * radius * radius;
}

final フィールドの値は、初期化リストで計算することができます:

class Product {
  final String name;
  final String sku;
  
  Product(this.name) : sku = 'SKU-${name.toUpperCase()}';
}

主な違い:

  • final: 実行時の値、インスタンスごとに異なる可能性がある
  • static const: コンパイル時定数、すべてのインスタンスで共有される
  • インスタンスフィールドを直接 const にすることはできません。static const のみが許可されます。

自分で試してみよう

import 'product.dart';

void main() {
  // TODO: 基本価格 999.99 で 'Laptop' という名前の Product を作成してください
  
  // TODO: 基本価格 29.99 で 'Mouse' という名前の Product を作成してください
  
  // TODO: 各製品に対して順番に(最初に 'Laptop'、次に 'Mouse')display() を呼び出してください
  
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン