Zenn
Open22

フラツターメモsyogaku

道上Y道上Y

return () { ... };
無名関数(anonymous function)

関数を返している」
つまり「関数を作って、それ自体を返す」

Function createRecipe() {
  return () {
    print('今日はカレーを作るよ');
  };
}

void main() {
  var recipe = createRecipe();//関数を受け取っている
  recipe();//受け取った関数を実行
道上Y道上Y

高階関数シンプル 「レシピを受け取って料理を作る料理人」

-型指定しないVar

void cook(Function recipe) {
   print('材料を準備して...');
   recipe();
   print('盛り付けて完成!');
}

void pastaRecipe() {
  print('パスタを茹でてソースを絡める');
}

void main() {
  cook(pastaRecipe);
}

型を指定しなければ抽象度が高くても許容される自由さがある

型指定するvar

void cook(void Function() recipe) {
print('材料準備!');
recipe();
print('完成!');
}

void pastaRecipe() {
 print('パスタを作っているよ');
}

void main() {
  cook(pastaRecipe);
}

必ず引数も戻り値もない関数を渡すルールがある

道上Y道上Y

高階関数シンプル 続・「レシピを受け取って料理を作る料理人」

戻り値がある関数の型指定var

void cook(int Function() recipe) {
  print('材料準備!');
  int result = recipe();
  print('出来上がった料理の美味しさレベルは $result 点!');
}

int pastaRecipe() {
  print('パスタを作ってるよ!');
  return 95;
}

void main() {
  cook(pastaRecipe);
}

int Function() recipe→intを返す関数をrecipeという引数として受け取る関数

出力の順番
材料準備! cook() 関数内
パスタを作ってるよ pastaRecipe() 関数内
味のスコアは 95 点! cook() 関数内

道上Y道上Y

無名関数(匿名関数)
名前を持たない関数

var func = (int x){
 return x * 2;
};

無名関数 = 名前なしで{}ブロックで定義

道上Y道上Y

ラムダ式(矢印関数)
行で処理&返却を書く関数の省略記法。

var func (int x)=> x * 2;
道上Y道上Y

map のイメージ

final numbers =[1,2,3,4];
final doubled = numbers.map((n) => n * 2).toList();
print(doubled);

mapはそれぞれの要素(n)をn*2にマッピングしている
マップ=変換する

道上Y道上Y

Flutterにおけるオブジェクト指向とは

flutterのベースであるDart言語が「オブジェクト指向プログラミング(OOP)」の概念に基づいている

OOP:Object-Oriented Programming

プログラムの中で、データとそのデータを扱う処理を1つのまとまり(=オブジェクト)として管理し、
この「オブジェクト」を部品のように組み合わせて、大きなシステムを作る考え方

主な概念として
・クラス-オブジェクトの設計図。どんなデータを持ち、どんな動きをするかを定義するもの。
・オブジェクト-クラスから作った実体(実物)。実際に使われるモノ。
・継承-あるクラスの機能を引き継いで、新しいクラスを作ること。
・カプセル化-データをオブジェクト内に隠し、外部から勝手に変更できないようにすること。
・ポリモーフィズム(多態性)-同じ名前のメソッドでも、オブジェクトごとに異なる動作をさせられる性質。


・クラス:車クラス(Car)を作成
→速度や色などの情報(プロパティ)、走る・止まるといった動作(メソッド)

・オブジェクト:
→そのクラスから「赤いスポーツカー」や「青いトラック」といった実物を作成。

道上Y道上Y

オブジェクト指向のインスタンス化 → 利用

クラスを作成(設計図を作成)

class Ingredient {
  final String name;
  final int spiciness; // 辛さレベル(1〜10)
//コンストラクタ(プロパティの初期化)
  Ingredient(this.name, this.spiciness);
}

インスタンスを作成(実態の作成)

final chili = Ingredient('唐辛子',9);
final pepper = Ingredient('黒コショウ',3);
final curryPowder = Ingredient('カリーパウダー',5);

出力

void main() {
  print('${chili.name}の辛さは${chili.spiciness}');
  print('${pepper.name}の辛さは${pepper.spiciness}');
  print('${curryPowder.name}の辛さは${curryPowder.spiciness}');
}
道上Y道上Y

高階関数

class Ingredient {
  final String name;
  final int spiciness; //からさレベル(1~10);

  Ingredient(this.name, this.spiciness);
}

List<String> filterMapAndSortBySpiciness(
  List<Ingredient> ingredients,
  bool Function(Ingredient) filter,
  String Function(Ingredient) mapper,
) {
  // フィルター&マッピング
  List<Ingredient> filtered = ingredients.where(filter).toList();

  // 辛さレベルでソート
  filtered.sort((a, b) => b.spiciness.compareTo(a.spiciness));

  // マッピング
  return filtered.map(mapper).toList();
}

// フィルターとマッパー
bool isSpicy(Ingredient ingredient) => ingredient.spiciness >= 5;

String decorateForCurry(Ingredient ingredient) =>
    '${ingredient.name} (辛さレベル: ${ingredient.spiciness})';

void main() {
  List<Ingredient> ingredients = [
    Ingredient('じゃがいも', 1),
    Ingredient('スパイスミックス', 8),
    Ingredient('鶏肉', 2),
    Ingredient('唐辛子', 10),
    Ingredient('ブラックペッパー', 6),
    Ingredient('玉ねぎ', 1),
  ];

  List<String> spicyIngredients = filterMapAndSortBySpiciness(
    ingredients,
    isSpicy,
    decorateForCurry,
  );

  print(spicyIngredients);
}
道上Y道上Y

プロパティの概念

プロパティ とは、クラスやウィジェットが持っている「設定項目」や「状態」を指します。
言い換えると、そのウィジェットが「どう表示されるか」「どんな挙動をするか」を決めるもの

//すべて「AppBar のプロパティ
AppBar(
  title: Text('タイトル'),
  backgroundColor: Colors.blue,
  centerTitle: true,
  elevation: 4,
)

プロパティ 型 説明
-title Widget? AppBar に表示するタイトル (通常 Text ウィジェットを入れる)
-backgroundColor Color? 背景色
-centerTitle bool? タイトルを中央に寄せるかどうか
-elevation double 影の高さ(立体感)

classで定義した変数も「プロパティ」になる

//final String title; も MyHomePage クラスの「プロパティ」です。
class MyHomePage extends StatefulWidget {
  final String title;
  const MyHomePage({super.key, required this.title});

  
  State<MyHomePage> createState() => _MyHomePageState();
}

【なぜプロパティを定義するのか?】
-そのウィジェットの「設定値」や「状態」を保持しておくため
Flutter ではウィジェットは再ビルド(再描画)されても、渡された値を元に表示を再構築します。

class MyHomePage extends StatefulWidget {
  final String title;   // ← このページがどんなタイトルで表示されるかを「保存」しておくため

  const MyHomePage({super.key, required this.title});

【再利用性のため】
プロパティを定義しておけば、同じ MyHomePage クラスを色々なタイトルで再利用できます。

MyHomePage(title: 'ホーム')
MyHomePage(title: '設定画面')

「中身のロジックは共通だけど、表示は変えたい」
➡ だからプロパティを持たせる

【コンストラクタを通じて受け渡した値を、そのウィジェットの中で使うため】
Flutter の StatelessWidget や StatefulWidget は final なプロパティを持っており、その値を build メソッド内で参照します。
これにより、ウィジェットは「引数として渡された情報を元に、自分自身をレンダリングする」ことができます。

--イメージ--
「ウィジェットは設計図」

  • 設計図には「部品表(プロパティ)」が必要
  • それをもとに実物(画面)が組み上がる

【逆にプロパティがない場合】

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  
  State<MyHomePage> createState() => _MyHomePageState();
}

このウィジェットは「外部からの値を一切受け取れない」ことになり、固定値しか表示できない

【まとめ】
-プロパティは「値を保存するため」であり
-「そのウィジェットが必要とする情報」を保持するため
-「柔軟に再利用」するため
-「引数を受け取って表示内容を変える」ため

道上Y道上Y

ステート
【StatelessWidget の役割】
-一度決められたデータ(プロパティ)を元に、UIを一回描画するだけのウィジェット。
-内部で状態を持たず、変化しない表示に使う。
-外部から受け取った値を final で保持し、それを build() 内で使ってUIを作る。
例:

class MyText extends StatelessWidget {
  final String text;
  const MyText({super.key, required this.text});

  
  Widget build(BuildContext context) {
    return Text(text); // text は変わらない
  }
}

【StatefulWidget の役割】
-外部から渡された「固定の情報(プロパティ)」を受け取り、状態を持つことができるウィジェットを作るためのクラス。
-実際に「状態」を持つのは State クラスで、この StatefulWidget はあくまで「状態を持つウィジェットを作るための土台」。
-自分では状態を持たず、createState() で状態を管理するクラス(State)を作り出すだけ。
例:

class CounterPage extends StatefulWidget {
  final String title;
  const CounterPage({super.key, required this.title});

  
  State<CounterPage> createState() => _CounterPageState();
}

-CounterPage はタイトルだけを持っていて、カウントの状態は State 側が持つ。

【State クラスの役割】
-StatefulWidget の「中の状態(変化する値)」を持ち管理する場所。
-setState() を呼ぶことで、状態を更新してUIを再描画させる。
-build() メソッド内では、親である StatefulWidget から渡されたプロパティも参照可能(widget.〇〇 として)。

class _CounterPageState extends State<CounterPage> {
  int _count = 0;

  void _increment() {
    setState(() {
      _count++;
    });
  }

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text(widget.title), // ← StatefulWidget のプロパティを参照
        Text('$_count'),    // ← 状態を持って変化する部分
        ElevatedButton(
          onPressed: _increment,
          child: const Text('増やす'),
        ),
      ],
    );
  }
}
項目 StatelessWidget StatefulWidget State クラス
主な役割 一度決まったUIを描画 状態を持つUIの土台 実際の状態を持ち UI を更新する
状態を持てるか 持てない 自身は持たない(State クラスが持つ) 状態を持つ場所
値の変更 再生成で変更対応 setState() を通じて変更に対応 状態変更と UI 再描画を管理
道上Y道上Y

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'AnimatedContainer Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const MyHomePage(title: 'AnimatedContainer Demo'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: const Center(child: AnimatedContainerApp()),
    );
  }
}
  const MyHomePage({super.key, required this.title});

required this.titleとあるので,MyHomePageはインスタンス化される時に必ずtitleを受け取る
つまり
MyApp → MyHomePage に title を渡していて←Widget ツリー構造の原理から渡される
MyHomePage クラスはそれを final String title; で受け取り
AppBar 内で Text(title) として使用しています。

MyApp → MyHomePage に title を渡す構造は、
「上位のWidgetから下位のWidgetにデータを渡してUIを構築する」という Flutter の基本的な設計パターンに基づいている

「コードのスコープを超えているように見える理由」

MyApp クラスと MyHomePage クラスは別々に定義されてるが
MyApp の build メソッド内で MyHomePage をインスタンス化している

home: const MyHomePage(title: 'AnimatedContainer Demo'),

この時点で MyApp の「中」で MyHomePage を「生成」しているので、MyApp → MyHomePage の関係は完全にスコープ内になる

MyApp は「親Widget」

MyHomePage は「子Widget」

親Widgetは、子Widgetをインスタンス化するときに title などの引数を渡せる
という仕組み
宣言的UI

道上Y道上Y

【Flutter の主要な概念まとめ】

宣言的UI

-状態に基づいてUIを「宣言」するだけ。
-状態が変われば UI は自動で再構築。
-build() メソッドで「この状態ならこう表示」と書く

Widget ツリー

-Flutter のUIはすべて「Widget」で構成。
-小さなWidgetを組み合わせてUIを作っていく。
-親Widget → 子Widget とデータを渡してツリー状に組み立てる。
-ツリーは build() 毎に再構築されるけど、軽量なので問題ない。

State(状態)管理

-StatelessWidget:状態を持たない。渡されたものだけでUIを描画。
-StatefulWidget:状態を State クラス内に持ち、setState() で更新。
-大きくなると Riverpod、Bloc、Provider など外部パッケージで状態管理することも。

ホットリロード・ホットリスタート

-Flutter の爆速開発を支える概念。
-変更を保存すると一瞬でUIに反映(ホットリロード)。
-状態を初期化してリスタートする場合はホットリスタート。

ビルドと再ビルド

-状態が変わるたびに build() が呼ばれてUIが再描画される。
-ただし「Widgetツリーの差分」をFlutterエンジンが最適化してくれるので負荷は低い。

Composition(コンポジション)

-大きなWidgetを作るより、小さなWidgetを組み合わせる思想。
-再利用性・可読性が高まる。

イミュータブル

-すべての Widget は基本的に「変更不可」(immutable)。
-状態が変わったときはWidgetを「作り直す」。
-でも内部的に差分だけを描画してるのでパフォーマンスは良い。

BuildContext

-「今、自分がWidgetツリーのどこにいるか」という情報を持ったオブジェクト。
-親Widgetから値を取得したり、ナビゲーションしたりするときに必須。
-context が分かるとツリー間のやりとりが理解しやすくなる。

Material Design / Cupertino

-Flutterは Material Design (Android風UI) と Cupertino (iOS風UI) 両方に対応している。
-1つのコードでクロスプラットフォームにできる。

-ページ遷移は Navigator.push() / Navigator.pop() を使う。
-ページは Route として管理される。

道上Y道上Y

BuildContextとは

-自分がWidgetツリーのどこにいるかを表すもの」
-親Widgetやツリー上にある情報にアクセスするための“参照ポイント”

抽象:
「Widgetツリーの森の中で、自分がどの木の枝に立っているかを教えてくれる地図のピン」みたいなもの。
メタ思考のようなもの

//親Widgetの情報を取得するとき
Theme.of(context).colorScheme.primary

context を通じて「自分より上にあるTheme」の情報を取得している

//ナビゲーション(画面遷移)するとき
Navigator.of(context).push(...)
//Scaffold を探して取得する
Scaffold.of(context)

子Widgetの中で親の Scaffold を使いたいときにも context が必要

context を使って、「この位置から画面遷移を開始という」という合図をしている。

なぜ「context」が必要か

-FlutterのUIは入れ子構造(ツリー)で、
上にあるWidget(親)が持っている情報を取得したいときに、
「自分がツリーのどこにいるか」を知らないと辿れないから。
つまり:
context を使うと、自分より上にある情報にアクセスできる

contextの「階層」を意識する

context は「そのWidgetの位置」なので、
子Widgetのcontextからは親の情報を取れるけど、逆はできない。
(親のcontextで下の階層を探しても見つからない)

応用
Builder ウィジェットを使って context を切り替える
例えば Scaffold の中で context を使いたいけど、
位置的に Scaffold より上の context しかない場合:

Scaffold(
  body: Builder(
    builder: (context) {
      // ここなら Scaffold.of(context) が使える
      return ElevatedButton(
        onPressed: () {
          final scaffold = Scaffold.of(context);
          scaffold.showSnackBar(SnackBar(content: Text('Hello')));
        },
        child: Text('Show Snackbar'),
      );
    },
  ),
);
//Builder を使うことで「ここから新しい context を作り直す」イメージ。

まとめ
-よく使う場所
build(BuildContext context) メソッド、Navigator、Theme取得、Scaffold操作など

-気をつけること
initState では使わない! 親のcontextでは子を辿れない!

道上Y道上Y

参考
https://zenn.dev/urasan/articles/f6613470658de1#dartにおけるconcurrency-と-parallelism

【並列処理と並行処理】

並行処理(Concurrency)と並列処理(Parallelism)

並行処理(Concurency)

・CPUが1つでも可能
・A・B・Cという処理を素早く切り替えながら進めて「同時に進んでいるように見せる」
・あくまで「同時進行感」
例:

Aの処理(ちょっと進める)
→Bの処理(ちょっと進める)
→Aに戻って続きを進める
→Cの処理進める
→これを超高速で切り替える

同時にやってるっぽいけどやってない感じ

並列処理(Parallelism)

・CPUコアが複数あるorマルチスレッド対応している場合
・本当に複数の処理が同時に走っている状態
例:

CPUコア1→Aの処理
CPUコア2→Bの処理
CPUコア3→Cの処理
本当に同時進行!

【わかりやすい例え】
・並行処理→1人のインド人が「オニオンを切りつつ、スパイスをいりながら、タンドゥールに手を入れてナンを焼いている」を順番に切り替えてやっている感じ」
・並列処理→3人のインド人がそれぞれカリーセットを出すために同時に調理している感じ

【Dart / Flutter に当てはめると】
・並行処理→async/awaitで非同期処理を切り替えながら進める
・並列処理→Isolate(別プロセス的に動く処理)、もしくはOSレベルのマルチコア処理

Dart の async/await は「並行処理」
Dart の Isolate は「並列処理」

【まとめイメージ図】
並行処理 → 実際は順番にちょっとずつ、でも同時っぽく動く
並列処理 → 本当に複数で同時に動く

道上Y道上Y

「Dartの非同期イベント処理の仕組み」

参考
https://zenn.dev/urasan/articles/f6613470658de1#dartにおけるconcurrency-と-parallelism


Dart(Flutter)の「イベント処理の流れ

Event Queue(イベントキュー)

→「やることリスト」にイベント(タップや再描写)が並んで待っている場所。
例:タップしたり、画面を書き直したりする命令が順番待ちしてる。
・物理→ユーザーがタップした
・システム→アニメーションを再描画したい
・コード→Futureが終わったよ

Event Loop(イベントループ)

→「次、誰の番?」と順番にキューから一個ずつイベントを取り出す仕組み。
言語化→次、どれをやる?」ってイベントキューを覗いて、
1個取り出して Main Isolate に渡します。
ずーっとグルグル回って、次の仕事が来るまで監視してる存在。

Main Isolate(メインアイソレート)

→イベントを受け取って実際に処理(タップの処理や、画面の再描写)を行う場所。
言語化→おっしゃ、きた!」
イベントループから渡されたタスクを実行する人。
UI更新・タップ反応・軽い処理などを担当。

概要

イベントループモデル(Event Loop Model)
もしくは
Dart concurrency model(Dartの並行処理モデル)

抽象的な駆動

Event Queue(やることリスト)

Event Loop(順番係:次やるものを取り出す)

Main Isolate(実際にそのタスクを処理する人)

という順番で作動する

具体的な駆動

【ユーザーがタップ】
 ↓
[ Event Queue ] に「タップイベント」が追加
 ↓
[ Event Loop ] 「次はタップイベントね!」と取り出す
 ↓
[ Main Isolate ] がそのタップ処理を実行する

【補足】
Event Loop は「選別」や「振り分け」はしないです。
→ ただひたすら順番通りに Main Isolate にタスクを渡します。

Main Isolate は「渡されたものだけやる」。自分からキューを探しに行くことはありません。

道上Y道上Y

Isolate(イソレート)

Dart(Flutter)が持つ「並列処理」を実現する仕組みで、完全に独立した処理の単位です。
Dartはシングルスレッドで動きますが、Isolateを使うことで「別スレッドのように同時に処理」できるようになる。

【イメージ】
・Main Isolate = UI担当(メインの人)
・Worker Isolate = 裏方スタッフ(別室で重たい処理をやってくれる人)

【特徴】
・1つのIsolateは、自分専用のイベントループとキューを持っている
・複数のIsolateはメモリを共有しない(完全独立)
・データの受け渡しは「ポート通信」(SendPort/ReceivePort)で行う

【Isolateが必要な理由】
・Flutterのメインスレッド(Main Isolate)はUI描画やタップ処理で忙しい
・重たい処理(画像処理、暗号化、ファイル読み込みなど)をここでやるとUIがカクつく

なので、重い処理は別のIsolateでやって結果だけもらう

Isolateを使う方法(2種類)

・自分でisolateを立ち上げる

Isolate.spawn(myHeavyFunction,myParameter);
//完全に独立した並列実行がスタートする

Flutterで簡単に使える compute()

final result = await compute(myHevyFunction,myParameter);
//内部でIsolateを立ち上げてくれて、終わったら結果を返してくれる便利関数らしい

具体的な使い方と使うべき場面

メインスレッド(UIスレッド)をブロックするような重たい処理を行いたいとき

例えば:
大量データの計算処理
複雑なJSONパース
大きいファイルの圧縮や画像処理
機械学習系の推論や数値計算
長時間かかる暗号化・復号処理
↑これをメインスレッドでやると、UIがフリーズしてしまうのでIsolateで並列処理をさせる

【メイン関数でisolateを起動】

void heavyTask(SendPort sendPort) {
  //ここで重たい処理
 int result = 0
 for (int i = 0; 1 < 11451481088888; i++) {
 result +=i;
}
//計算結果を Isolate 呼び出し元に送信
sendPort.send(result);
}
import 'dart:isolate';
void main() asyn {
print('処理開始');

//通信用ポートを作成
final receibePort = Receive();

//Isolate 起動
await Iso;ate.spawn(heavyTask, receivePort.sendPort);

//結果を待つ
receivePort.listen((result) {
  print('計算結果: $result');
  receivePort.close();
});
print('Isolate に投げたあとでも他の処理は継続できる');
}

メモ
・ReceivePort 作成→メイン側で結果を受け取るためのポートを作成
・Isolate.spawn()→重たい処理を持った関数と sendPort を渡して起動
・receivePort.listen()→ 結果を受け取り次第UI更新やログ出力
・通信はポート経由→値を直接返せないので sendPort.send() でやりとり

【実運用の例】
・UI で「計算中...」スピナーを回しつつ、
・Isolate に投げて
・終わったら結果を受け取って setState() してUI更新

【注意点】
・関数に渡すデータは シリアライズ可能なもの(プリミティブ型 or List / Map) に限られる
・BuildContext などを直接渡すことはできない
・値渡しの世界なので、重たいオブジェクトをそのまま渡すのは非推奨

道上Y道上Y

SendPort/ReceivePort

isolate同士はメモリを共有しないため「ポート」を通じてメッセージを送受信する必要がある

SendPort(送信側subisolate側)

isolate側ではSendPortで受け取る

void myIsolateEntry(SendPort sendPort) {
  sendPort.send("処理完了");
}

-SendPort型はdart:isolateライブラリに含まれているクラス。
-Isolate(アイソレート)間でデータを送るときに使う「送信用ポート」を表す。

ReceivePort

mainisolare側ではReceivePortで受け取る

final receivePort = ReceivePort();
Isolate.spawn(myIsolateEntry, receuvePort.sendPort);

receivePort.spawn(myIsolateEntry, receivePort.sendPort);

receivePort.listen((message){
   print("受け取ったメッセージ: $message");
});
メモリ共有 内容 備考
なし Isolate間ではメモリ共有せず、データはコピー渡し 他のスレッドと直接やり取りせず安全に処理
並列実行 可能 メインアイソレートとは独立して同時並行処理可能
イベントループ 各Isolateが独立して所有 Main Isolate・Worker Isolate それぞれにある
データ通信 SendPort / ReceivePort を使用 メッセージベースでデータのやり取りを行う
主な用途 画像処理、重い計算、大量データ変換などUI負荷を避けたい処理 compute() で簡易的に使うことも可能
道上Y道上Y

シリアライズ

オブジェクト(インスタンス)をJSONやMap<String,dynamic>のような形式に変換すること
・ネットワーク越しにAPIに送ったり
・データベースに保存したり
・ファイルに保存したり
・SharedPreferencesに保存したり
できるようになる

デシリアライズ

JSONやMap<String,dynamic>からDartのオブジェクトに変換すること

それぞれの具体コード

class User {
  final int id;
  final String name;

 User({required this.id, required this.name});

  //JSON → User(デシリアライズ)
  factiry User.fromJson(Map<String,dynamic> json) {
    return User(
     id: json['id'],
     name: jdon['name'],
   );
)

//User → JSON(シリアライズ)
Map<String, dynamic> toJson() {
  return {
   'id':id,
   'name':name,
    };
   }
  }

自動でできる

json_serializable←パッケージ
//使う時書く

道上Y道上Y

プリミティブ型

・プログラミング言語における基本的なデータ型のこと。
・プリミティブ型とは、「int」や「bool」など、プログラムで基本的な情報を表すための“最小単位のデータ型”のこと。

Dart(Flutter)における主なプリミティブ型

int 42 整数。負の数もOK
double 3.14 小数(浮動小数点数)
num intとdoubleの親クラス
bool true, false 真偽値。条件分岐などに使用
String "こんにちは" 文字列(文字の並び)
Null null 値が存在しないことを示す
Symbol #foo メタプログラミング用途(特殊な場面で使う)
Runes Runes('✨') Unicodeコードポイント(文字列の低レベル操作)

道上Y道上Y

compute() 関数

//あとでやる

import 'package:flutter/foundation.dart';

int heavyComputation(int value) {
  // 例: 時間がかかる重い処理
  int result = 0;
  for (int i = 0; i < value; i++) {
    result += i;
  }
  return result;
}

void main() async {
  int result = await compute(heavyComputation, 100000000);
  print(result); // 重い計算結果が出る
}
道上Y道上Y

null合体演算子(null-coalescing operator)

? クエスチョン 「nullを許す」型(nullable)にする。例:int?
! バン(bang) 「絶対nullじゃない!」と明示(nullチェック済とみなす)
?? null合体 左がnullなら右を使う。例:x ?? 10
?. セーフアクセス nullならスキップ、nullじゃなければ実行
??= null代入 左がnullのときだけ代入する。例:x ??= 100

//null許容型
int? age; // nullでもOKなint型
age = null; // OK

//nullじゃないと信じて使う(危険なやつ)
int? age = 30;
print(age! + 1); // ageがnullじゃないと信じて +1する

int? age2 = null;
// print(age2! + 1); // ← これはクラッシュする(nullだから!)

//nullのときにデフォルト値を使う
int? age;
int displayAge = age ?? 18; // ageがnullなら18になる

//nullを避けてアクセス(セーフアクセス)
String? name;
print(name?.length); // nameがnullならnull、nullじゃなければlength
// userがnullならこの式もnullで終わる
User? user;
print(user?.name); // userがnullならこの式もnullで終わる

//nullなら代入する
int? age;
age ??= 25; // ageがnullなら25を代入
print(age); // 25

age ??= 30; // もうnullじゃないから変わらない
print(age); // 25のまま

まとめ
・? は「null許容」
・! は「nullじゃないと信じる」
・?? は「nullなら代わりを使う」
・?. は「nullなら何もしない」
・??= は「nullなら代入」

作成者以外のコメントは許可されていません