Dart 基本構文 — プログラム構造・コメント・コード

構文はコードの骨格である — 標準化された構文の習慣が、コードの可読性と保守性を決める。

1. 学べること


2. 開発者のリアルな物語

(1) 課題:コメント不足で保守不能なコードに

Charlie は前任者から受け継いだデータ処理スクリプトにコメントが一切なかった。マジックナンバーと略語だらけの 500 行のコードの中で、pproduct を、ttaxRate を表していることを理解するのに 3 日かかった。さらに悪いことに、重要な税計算ロジックにはドキュメントコメントがなく、新しい同僚がそれをバグだと勘違いして修正してしまった。結果として 2,000 件の注文で税計算が誤りになり、5 万ドルの直接的な損失が出た。

(2) 標準化された構文による解決

Dart は 3 種類のコメントを提供する。dart format による自動フォーマットと dart analyze による静的チェックを組み合わせれば、構造が明確でよくコメントされたコードを書ける。

DART
/// Calculates the tax amount for an order.
///
/// Uses the regional tax rate and applies exemptions
/// for orders below the minimum threshold.
double calculateTax(double amount, double taxRate, {double exemptThreshold = 0}) {
  // Apply exemption threshold
  if (amount <= exemptThreshold) return 0;

  /* Complex tax calculation logic
     that may span multiple lines */
  final taxableAmount = amount - exemptThreshold;
  return taxableAmount * taxRate;
}
TEXT
> 出力: ローカルの DartPad または `dart run` で実行してください。この Dart コースの全例は Dart 3.x / Flutter 3.x ベースです。SDK バージョンにより結果が多少異なる場合があります。

(3) 効果


3. プログラム構造と main エントリポイント

(1) プログラム実行モデル

すべての Dart プログラムは main() 関数から実行を開始する。Dart はシングルスレッドのイベントループモデルを採用しているが、Isolate によって並列処理を実現できる。

100%
graph TD
  A[OS が Dart VM をロード] --> B[main 関数を検出]
  B --> C[main 本体を実行]
  C --> D{非同期操作があるか?}
  D -->|いいえ| E[プログラム終了]
  D -->|はい| F[イベントループが動作]
  F --> G[マイクロタスクを処理]
  G --> H[イベントを処理]
  H --> I{まだイベントがある?}
  I -->|はい| G
  I -->|いいえ| E
TEXT
> 出力: ローカルの DartPad または `dart run` で実行してください。この Dart コースの全例は Dart 3.x / Flutter 3.x ベースです。SDK バージョンにより結果が多少異なる場合があります。

▶ サンプル:main 関数の基本形

DART
// 最もシンプルな main 関数
void main() {
  print('DataPipeline starting...');
}
TEXT
> 出力: ローカルの DartPad または `dart run` で実行してください。この Dart コースの全例は Dart 3.x / Flutter 3.x ベースです。SDK バージョンにより結果が多少異なる場合があります。

▶ サンプル:引数付き main 関数

DART
// コマンドライン引数付きの main
void main(List<String> arguments) {
  // arguments[0] は最初の引数(プログラム名ではない)
  print('Arguments received: $arguments');
  print('Argument count: ${arguments.length}');
}
TEXT
> 出力: ローカルの DartPad または `dart run` で実行してください。この Dart コースの全例は Dart 3.x / Flutter 3.x ベースです。SDK バージョンにより結果が多少異なる場合があります。
main の形式 シグネチャ 用途
引数なし void main() シンプルなスクリプト
引数あり void main(List<String> args) CLI ツール
戻り値あり Future<void> main() 非同期エントリポイント

4. セミコロン、波括弧、インデント

(1) 基本的な構文ルール

Dart は文の終わりにセミコロン ; を、コードブロックの囲みに波括弧 {} を使用する。インデントは 2 スペース(dart format で強制される)。

▶ サンプル:セミコロンと波括弧

DART
void main() {
  // 各文の終わりにセミコロン
  int orderCount = 1000;
  double totalAmount = 50000.0;

  // ブロック本体には波括弧が必須
  if (orderCount > 0) {
    print('Processing $orderCount orders');
  } else {
    print('No orders to process');
  }
}
TEXT
> 出力: ローカルの DartPad または `dart run` で実行してください。この Dart コースの全例は Dart 3.x / Flutter 3.x ベースです。SDK バージョンにより結果が多少異なる場合があります。
ルール 説明 dart format の挙動
末尾のセミコロン すべての文の終わりに ; 自動では付与しない
波括弧 if/for/while は {} 必須 自動フォーマット
インデント 2 スペースインデント 自動修正
行幅 80 文字以内を推奨 強制ではない

5. 3 種類のコメント

(1) 行コメント //

単一行の説明に使われ、もっとも一般的である。

▶ サンプル:行コメント

DART
void main() {
  // データパイプラインを初期化
  final maxRecords = 1000000; // 処理する最大レコード数

  // TODO: 設定ファイルのサポートを追加
  print('Max capacity: $maxRecords records');
}
TEXT
> 出力: ローカルの DartPad または `dart run` で実行してください。この Dart コースの全例は Dart 3.x / Flutter 3.x ベースです。SDK バージョンにより結果が多少異なる場合があります。

(2) ブロックコメント /* */

複数行の説明やコードの一時的な無効化に使う。

▶ サンプル:ブロックコメント

DART
void main() {
  /* このセクションは DataPipeline 設定の
     初期セットアップを扱う。
     環境変数から読み込む。 */
  final config = 'production';

  /*
  // デバッグ用に一時的に無効化
  if (config == 'production') {
    enableLogging();
  }
  */
}
TEXT
> 出力: ローカルの DartPad または `dart run` で実行してください。この Dart コースの全例は Dart 3.x / Flutter 3.x ベースです。SDK バージョンにより結果が多少異なる場合があります。

(3) ドキュメントコメント ///

API ドキュメントの生成に使われ、Markdown 形式に対応する。

▶ サンプル:ドキュメントコメント

DART
/// Represents an e-commerce order with tax calculation.
///
/// This class models a single order from the DataPipeline
/// system, including amount, tax rate, and status.
///
/// Example:
/// ```dart
/// final order = Order(id: 'ORD-001', amount: 1500.0);
/// print(order.totalWithTax);
/// ```
class Order {
  final String id;
  final double amount;

  Order({required this.id, required this.amount});

  double get totalWithTax => amount * 1.08;
}
TEXT
> 出力: ローカルの DartPad または `dart run` で実行してください。この Dart コースの全例は Dart 3.x / Flutter 3.x ベースです。SDK バージョンにより結果が多少異なる場合があります。
コメントの種類 構文 用途 ドキュメント生成
行コメント // コード説明、TODO なし
ブロックコメント /* */ 複数行説明、コード無効化 なし
ドキュメントコメント /// API ドキュメント あり(dart doc)

6. キーワードと予約語

(1) Dart キーワードの分類

カテゴリ キーワード 説明
宣言 class enum mixin extension typedef 型宣言
修飾子 abstract sealed final const late static 修飾子
制御 if else for while do switch return フロー制御
例外 try catch finally throw rethrow 例外処理
非同期 async await sync yield 非同期プログラミング
int double String bool dynamic void 組み込み型
Null 安全性 null late required Null 安全性

▶ サンプル:予約語の識別子使用を避ける

DART
// 正しい - 意味のある名前を使う
int orderCount = 100;
String customerName = 'Alice';
double taxRate = 0.08;

// 間違い - 予約語の識別子使用を避ける
// int class = 5;     // 構文エラー!
// String function = 'test'; // 構文エラー!
TEXT
> 出力: ローカルの DartPad または `dart run` で実行してください。この Dart コースの全例は Dart 3.x / Flutter 3.x ベースです。SDK バージョンにより結果が多少異なる場合があります。

7. 文と式

(1) コアな違い

は戻り値を持つが、は持たない。これは Dart の構文を理解するうえで基礎となる。

100%
graph TD
  A[コード単位] --> B[式<br/>値を持つ]
  A --> C[文<br/>値を持たない]
  B --> B1[リテラル: 42]
  B --> B2[変数: count]
  B --> B3[演算: a + b]
  B --> B4[関数呼び出し: max(1, 2)]
  C --> C1[if-else]
  C --> C2[for ループ]
  C --> C3[return 文]
  C --> C4[変数宣言]
TEXT
> 出力: ローカルの DartPad または `dart run` で実行してください。この Dart コースの全例は Dart 3.x / Flutter 3.x ベースです。SDK バージョンにより結果が多少異なる場合があります。

▶ サンプル:式と文

DART
void main() {
  // 式 - 値を生成する
  int count = 100;              // 100 は式
  double price = 29.99;         // 29.99 は式
  double total = price * count; // price * count は式
  bool isExpensive = total > 1000; // total > 1000 は式

  // 文 - 値を生成しない
  if (isExpensive) {            // if 文
    print('High value order');  // print 呼び出し文
  }

  // Dart 3: switch 式(式である!)
  String label = switch (count) {
    0 => 'empty',
    <= 10 => 'small',
    <= 100 => 'medium',
    _ => 'large',
  };
}
TEXT
> 出力: ローカルの DartPad または `dart run` で実行してください。この Dart コースの全例は Dart 3.x / Flutter 3.x ベースです。SDK バージョンにより結果が多少異なる場合があります。
観点
戻り値 あり なし
入れ子 他の式の中にネスト可能 独立して実行される
a + bx > 0 ifforreturn
Dart 3 新機能 switch 式

8. 完全なサンプル:DataPipeline コードスタイルテンプレート

DART
// ============================================
// DataPipeline - コードスタイルテンプレート
// 正しい構文、コメント、構造を示す
// ============================================

/// Configuration for the DataPipeline processing engine.
///
/// Holds settings like maximum batch size, output format,
/// and whether to enable verbose logging.
class PipelineConfig {
  /// Maximum number of records per processing batch.
  final int batchSize;

  /// Output format for generated reports.
  final String outputFormat;

  /// Enable detailed processing logs.
  final bool verbose;

  /// Creates a new pipeline configuration.
  ///
  /// Default batch size is 10,000 records.
  /// Default output format is 'json'.
  PipelineConfig({
    this.batchSize = 10000,
    this.outputFormat = 'json',
    this.verbose = false,
  });

  /// Returns a human-readable summary of the config.
  String get summary =>
      'Batch: $batchSize records, Format: $outputFormat, Verbose: $verbose';
}

/// Entry point for DataPipeline CLI tool.
void main(List<String> arguments) {
  // Step 1: Load configuration
  final config = PipelineConfig(
    batchSize: 50000,
    outputFormat: 'csv',
    verbose: true,
  );

  // Step 2: Display configuration
  print('=== DataPipeline Configuration ===');
  print(config.summary);

  // Step 3: Process based on arguments
  /* TODO: Implement actual data processing
     - Read input source
     - Transform records
     - Write output report
  */
  final recordCount = arguments.isNotEmpty ? int.tryParse(arguments[0]) ?? 0 : 0;

  if (recordCount > 0) {
    print('Processing $recordCount records...');
  } else {
    print('No records specified. Use: dart run bin/main.dart <record_count>');
  }
}
TEXT
> 出力: ローカルの DartPad または `dart run` で実行してください。この Dart コースの全例は Dart 3.x / Flutter 3.x ベースです。SDK バージョンにより結果が多少異なる場合があります。

出力(dart run bin/main.dart 100000):

TEXT
=== DataPipeline Configuration ===
Batch: 50000 records, Format: csv, Verbose: true
Processing 100000 records...

❓ よくある質問

Q: Dart ではセミコロンは必須ですか? A: はい、Dart ではすべての文の終わりにセミコロンが必要です。Python/Go のように省略はできません。これは Dart 初心者がもっともよく犯すミスです。

Q: 行コメントとドキュメントコメントはいつ使い分けますか? A: 公開 API(クラス、公開メソッド、公開プロパティ)には /// ドキュメントコメントを使います。内部実装の詳細には // 行コメントを使います。dart doc はドキュメントコメントのみを処理します。

Q: dart format はコードロジックを変更しますか? A: いいえ。dart format は空白と改行を調整するだけで、コードの意味は変更しません。CI で --set-exit-if-changed を安心して使えます。

Q: Dart の if 文は波括弧を省略できますか? A: 文法上、続く文が 1 つだけなら波括弧を省略できます。ただし dart format は自動的に波括弧を追加します。常に波括弧を使うことを強く推奨します。

Q: switch 式と switch 文の違いは何ですか? A: switch 式(Dart 3)は戻り値を持ち、=> で分岐します。switch 文は戻り値が無く、case: で分岐します。前者の方が簡潔、後者の方が柔軟です。

Q: ドキュメントコメントには //// */ のどちらを使いますか? A: Dart は公式に /// を推奨しています。/ */ も有効ですが、/// が Dart コミュニティの主流スタイルであり、dart format/// を使うようにフォーマットします。

Q: main 関数は int を返せますか? A: Dart の main の戻り型は void または Future<void> です。プロセスの終了コードは dart:ioexit() 関数で設定できます。


📖 まとめ


📝 練習問題

  1. 基礎(難易度 ⭐):3 種類のコメントをすべて使った main 関数を書きましょう。dart doc . を実行して生成されたドキュメントの効果を確認してください。
  2. 中級(難易度 ⭐⭐):意図的に整形が悪い Dart コード(インデントの混在、波括弧の欠落)を数か所書いた後、dart format で自動修正してください。修正前後の違いを比較しましょう。
  3. 挑戦(難易度 ⭐⭐⭐):3 つのメソッドを含むクラスの完全なドキュメントコメント(説明、パラメータ説明、サンプルコードを含む)を書き、dart doc で HTML ドキュメントを生成して結果を確認してください。

← 前のレッスン | 次のレッスン →

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%