APP 開發

Dart 3.12 把 primary constructor 變成正式語法:少寫一半樣板,但它悄悄改寫你的 code review 習慣

2026.06.08 · 179 次瀏覽
Dart 3.12 把 primary constructor 變成正式語法:少寫一半樣板,但它悄悄改寫你的 code review 習慣

primary constructors 與 private named parameters 登場。打字變少、對 code generation 的依賴鬆動,但可讀性是要管理的取捨。

分享:

Dart 團隊在 Dart 3.12 的官方公告裡,正式把兩個語言級新功能交到開發者手上:primary constructors(主建構子)private named parameters(私有具名參數)。一句話總結:你以前要在 class body、參數列、初始化列表之間重複三次的欄位名稱與型別,現在可以濃縮成 class header 上的一行。primary constructors 仍標記為 experimental,private named parameters 則已穩定可用。對每天在寫 Flutter widget 的人來說,這是少數會直接改變你每天打字量的更新。

要懂這件事為什麼值得停下來看,得看 Dart 的歷史包袱。Dart 從 2.0 起就是一個安全但囉嗦的語言:宣告一個 immutable 的 model class,你得寫 final 欄位、再寫一個把每個欄位都 this.x 一遍的建構子,動輒十幾行樣板。社群為了逃避這件事,長年仰賴 freezedbuilt_value 這類 code generation 套件——但代價是 build_runner 的編譯時間、一堆 .g.dart 檔、以及新人看不懂的 macro 魔法。Dart 官方自己統計過:pub 套件裡超過五分之一(>20%)的欄位初始化,做的事情只是把一個和欄位同名、但前面少一個底線的參數,塞進私有欄位。primary constructors 就是要把這段最常見的樣板從語言層面消滅。

這對誰重要?所有寫 Flutter 的團隊——而 Flutter 在 2026 年仍是跨平台 App 的主力之一。少掉 build_runner,意味著大型專案的增量編譯能省下可觀時間;對接案工作室而言,model 層的開發速度直接影響報價競爭力。接下來拆解實際寫法、與 freezed 的取捨,以及一個多數教學不提的風險。

技術細節

primary constructors 讓你把參數直接宣告在 class header;private named parameters 則允許具名參數用底線開頭,編譯器自動幫你把它接到同名私有欄位,並對外去掉底線。

// Dart 3.11 以前:宣告一個 immutable model 要這麼多樣板
class Booking {
  final String _id;
  final DateTime _startAt;
  final int _seats;
 
  Booking({
    required String id,
    required DateTime startAt,
    required int seats,
  })  : _id = id,
        _startAt = startAt,
        _seats = seats;
}
 
// Dart 3.12:primary constructor + private named parameters
class Booking({
  required String _id,
  required DateTime _startAt,
  required int _seats,
}) {
  // 對外仍是 Booking(id: ..., startAt: ..., seats: ...)
}

analysis_options.yaml 開啟 experimental 旗標:

analyzer:
  enable-experiment:
    - primary-constructors

關鍵行為差異:對呼叫端來說,Booking(id: x, startAt: y, seats: z) 的 API 完全不變——底線只是內部慣例,編譯器在對外簽章自動脫掉。這是它和單純把參數設 public 最大的不同:你既保有封裝,又省掉初始化列表。

三類讀者的立刻行動

  • 工程師(程式碼級):升級 Dart SDK 到 3.12,先在新的 model class 試 private named parameters(已穩定),primary constructors 則開 experiment 旗標在一個小模組試水溫。先別整庫改寫。
  • 技術負責人(架構級):盤點 freezed / built_value 依賴。單純 model 評估用 primary constructors 取代、砍掉 build_runner;但有 copyWith、union types 需求的,freezed 仍無可取代。
  • 創業者/接案商(商業級):把「Dart 3.12 語法現代化 + 移除不必要的 code generation」做成小型技術債清理服務,交付週期短、效果可量化(編譯時間)。

比較與權衡

vs freezed:primary constructors 解的是樣板太多,但 freezed 解的是樣板 + copyWith + 相等比較 + union types + JSON 序列化一整包。只需要前者,就少一個依賴、少一輪 build_runner;重度依賴 copyWith 與 sealed union 的,freezed 暫時動不了。遷移成本:新專案幾乎零成本;舊專案建議只在新增 class 用新語法,不要為了統一風格大改既有 model。

不會告訴你的事

  • primary constructors 仍是 experimental。寫進 production,未來版本語法若微調得跟著改;對要長期維護的客戶專案是賭注。
  • 可讀性是雙面刃。class header 塞進一長串參數,一行裡藏五個欄位的型別與預設值,code review 時反而比攤開的初始化列表難逐項檢查。
  • 底線自動脫殼的規則對新人有學習曲線,_id 對外變 id 不看文件不直覺。

未來 3 個月會發生什麼

預期 primary constructors 逐步走向 stable,IDE 重構工具會跟上「把舊建構子一鍵轉成 primary constructor」。freezed 作者可能調整定位,主打 union 與序列化。待觀察指標:Flutter 官方 sample、starter template 何時改用新語法當預設。

我的觀點

主流會說 primary constructors 終於來了、Dart 變簡潔了。我的判斷不同:真正的贏家不是打字變少,而是對 code generation 的依賴開始鬆動。過去 Flutter 生態被 build_runner 綁架。primary constructors 不會一夕殺死 freezed,但它讓「不裝 code generation 也能寫出乾淨 model」第一次成為預設選項。對 ScriptWalker 的啟示:別急著全改寫,但在所有新接的 Flutter 案,從第一天就用 3.12 語法立規範——model 層更輕、編譯更快、交接更好讀。把「不背 build_runner 技術債」當成報價時的隱形競爭力。

資料來源

分享: