动态

详情 返回 返回

Dart的宏取消了,期待3年的功能,説沒就沒了? - 动态 详情

哈嘍,我是老劉

就在剛剛結束的Fluttercon EU 2025上,Google Dart團隊宣佈:投入數年時間、無數工程師心血的宏功能開發,徹底停止了!
在這裏插入圖片描述

這不是延期,不是推遲,而是直接砍掉!

這意味着從2022年開始,Dart團隊投入的所有資源、所有原型開發、所有技術攻關,全部歸零。

作為一個六七年的Flutter老兵,同時也是從C/C++時代走過來的開發者,我對這個消息的震驚程度,可能比很多人都要強烈。

因為我太清楚宏功能對於大型項目意味着什麼了。

在C/C++的世界裏,宏是大型項目的救命稻草。

在Flutter的世界裏,由於禁用了反射,我們失去了太多便利性。

比如JSON的自動解析,比如依賴注入,比如代碼生成...

這些功能現在只能通過build_runner這種笨重的方式來實現。

而宏,本來應該是更優雅、更高效的解決方案。

甚至比反射還要好!

但現在,這一切都沒了。

宏功能到底是個啥?

説到宏,很多Flutter開發者可能一臉懵逼。

畢竟Dart從來沒有過這個功能。

但對於我這種從C/C++時代走過來的老兵,宏簡直就是編程界的"變形金剛"。

簡單來説,宏就是一種在編譯時告訴編譯器"怎麼處理代碼"的機制。

想象一下,你寫了一段重複性很高的代碼,比如為每個數據類都要寫getter、setter、toString、hashCode...

宏可以讓你只寫一行註解,編譯器自動幫你生成這些代碼。

舉個例子,在Rust中,你只需要寫:

#define DECLARE_GETTER_SETTER(type, name) \
private: \
    type name##_; \
public: \
    type get##name() const { return name##_; } \
    void set##name(const type& value) { name##_ = value; }

class User {
    DECLARE_GETTER_SETTER(std::string, Name)
    DECLARE_GETTER_SETTER(int, Age)
};

一個簡單的宏定義,就能自動生成getter和setter方法。

如果沒有宏,你得手寫幾十行代碼!

在Flutter中,如果有了宏,我們可能只需要:

@JsonSerializable()
class User {
  final String name;
  final int age;
}

編譯器就自動生成fromJson、toJson方法。

不用再忍受build_runner那龜速般的代碼生成了!

這就是宏的第一個作用:減少代碼重複,提高可維護性。

但宏的威力遠不止於此。

更進一步,宏可以在編程語言的基礎上形成一套DSL(領域特定語言)。

比如在Rust中,你可以用宏創建自己的"小語言",讓代碼更貼近業務邏輯。

在C/C++中,宏更是大型項目的標配。

Linux內核、Chrome瀏覽器、各種遊戲引擎...

哪個不是宏滿天飛?

因為宏能讓複雜的系統變得簡潔、可讀、易維護。

這就是為什麼我對Dart宏功能如此期待的原因。

Flutter項目越來越大,代碼重複越來越多,build_runner越來越慢...

宏本來應該是解決這一切問題的銀彈。

揭秘真相:為什麼Google要砍掉這個"萬能神器"?

但是,理想很豐滿,現實很骨感。

Google為什麼要砍掉這個看起來如此完美的功能?

答案比你想象的更復雜。

第一個原因:技術野心太大,想一口喫成胖子

這裏有個關鍵細節,很多人都忽略了。

Dart團隊追求的不是簡單的語法級宏,而是"深度語義內省"。

什麼意思?

簡單的宏只是文本替換,就像C/C++的#define一樣。

但Dart團隊想要的是能夠理解代碼語義的智能宏。

比如,宏不僅要知道你定義了一個類,還要知道這個類的繼承關係、泛型參數、註解信息...

甚至要在代碼還在修改的時候,就能進行語義分析!

這就像是要求一個翻譯不僅要會翻譯文字,還要理解文化背景、歷史典故、雙關語...

技術難度直接從"困難"跳到了"地獄級"。

對比一下其他語言:

Rust的宏從簡單的macro_rules!開始,逐步演進到過程宏。

C++的宏雖然強大,但本質上還是預處理器的文本替換。

而Dart想要一步到位,直接做最複雜的語義宏。

結果就是:每解決一個問題,就冒出三個新問題。

第二個原因:性能噩夢,開發體驗殺手

這是最致命的問題。

Dart團隊發現,深度語義內省會帶來巨大的編譯時成本。

IDE的代碼補全變慢了。

靜態分析變慢了。

最要命的是,熱重載也變慢了!

熱重載是Flutter的殺手鐗功能,如果連這個都受影響,那宏功能就是在自掘墳墓。

想象一下,你改了一行代碼,本來1秒鐘就能看到效果。

現在因為宏的語義分析,要等5秒、10秒...

開發者會瘋掉的!

這就像是為了讓汽車更智能,結果把發動機搞得越來越重,最後車都開不動了。

第三個原因:無底洞效應,看不到終點

最讓Dart團隊絕望的可能是,這個問題似乎沒有邊界。

每當他們以為快要解決所有問題時,就會發現新的技術挑戰。

性能優化了一點,又發現內存佔用暴增。

內存問題解決了,又發現併發編譯有問題。

併發問題解決了,又發現增量編譯邏輯有bug...

就像是在玩打地鼠遊戲,永遠打不完。

團隊投入了數年時間,燒了無數資源,卻看不到成功的曙光。

繼續投入,可能是無底洞。

停止開發,至少能把資源用在其他地方。

第四個原因:機會成本太高

這是最現實的考量。

Dart團隊的人力資源是有限的。

把這些頂級工程師用在宏功能上,就意味着其他功能得不到開發。

比如性能優化、新的語言特性、工具鏈改進...

這些可能對開發者更有實際價值。

而且,宏功能即使做出來了,也不是所有開發者都會用。

但性能優化、工具鏈改進,每個開發者都能受益。

從投入產出比來看,砍掉宏功能可能是更明智的選擇。

第五個原因:替代方案基本夠用

説實話,雖然build_runner慢一點,但它能解決大部分問題。

json_annotation、freezed、retrofit...

這些第三方庫已經形成了相對成熟的生態。

雖然不如宏那麼優雅,但至少是可用的。

而且,Dart團隊承諾會大幅優化build_runner的性能。

如果build_runner能快10倍,那宏功能的必要性就大大降低了。

這就像是,雖然沒有了超級跑車,但普通汽車也能滿足日常需求。

看到這裏,你可能會問:那其他語言是怎麼做到的?

答案很簡單:它們沒有Dart這麼大的野心。

Rust的宏雖然強大,但它是逐步演進的,而且性能要求沒有Dart這麼苛刻。

C++的宏更是簡單粗暴,根本不考慮語義分析。

只有Dart,想要在保持極致性能的同時,實現最複雜的語義宏。

這就像是想要造一輛既能飛又能潛水還要比跑車快的交通工具。

Dart團隊的Plan B能拯救開發者嗎?

雖然宏功能沒了,但Dart團隊並沒有坐以待斃。

他們拿出了一套"Plan B",試圖用其他方式解決開發者的痛點。

説實話,這套方案雖然不如宏那麼性感,但可能更實用。

第一招:專門的數據類特性

Dart團隊承諾會推出專門針對數據類的語言特性。

什麼意思?

就是不用宏,也能優雅地處理數據序列化、比較、拷貝這些常見操作。

比如,未來可能會有這樣的語法:

data class User {
  final String name;
  final int age;
}

只要加個data關鍵字,編譯器就自動生成toString、hashCode、operator==、copyWith等方法。

這個思路其實很聰明。

與其搞複雜的宏系統,不如針對最常見的用例,直接在語言層面提供支持。

Kotlin就是這麼做的,效果相當不錯。

第二招:build_runner性能大提升

這是最實際的改進。

Dart團隊承諾會對build_runner進行徹底重構,目標是10倍性能提升!

如果真能做到,那現在的痛點就基本解決了。

想象一下,原來需要30秒的代碼生成,現在只要3秒。

原來需要5分鐘的全量構建,現在只要30秒。

雖然還是沒有宏那麼優雅,但至少不會讓人抓狂了。

而且,build_runner的生態已經很成熟,不需要重新學習。

第三招:Augmentations功能

這是最有意思的一個方案。

Augmentations可以理解為"宏的精簡版"。

它不能做複雜的語義分析,但能解決80%的常見需求。

比如,你可以用Augmentations給現有的類添加方法:

augment class User {
  String get displayName => '$name ($age歲)';
}

這樣就能在不修改原始類的情況下,擴展功能。

雖然沒有宏那麼強大,但對於大部分場景已經夠用了。

第四招:社區方案的官方加持

Dart團隊還承諾會更深度地支持社區方案。

比如freezed、json_annotation、retrofit這些庫,可能會得到官方的性能優化支持。

甚至可能直接集成到Dart SDK中。

這樣一來,雖然還是第三方庫,但體驗會更接近原生功能。

給開發者的實用建議

面對這個現實,我們該怎麼辦?

1. 擁抱現有方案,別等了

如果你還在等宏功能,可以停止了。

freezed + json_annotation的組合已經很成熟,完全可以滿足大部分需求。

雖然代碼生成慢一點,但至少穩定可靠。

2. 關注build_runner的性能優化

Dart團隊承諾的10倍性能提升,如果真能實現,會徹底改變遊戲規則。

建議密切關注相關更新,第一時間升級。

3. 學習Augmentations

這個功能雖然還在實驗階段,但很有前景。

提前瞭解語法和用法,等正式發佈時就能立即上手。

4. 優化現有的代碼生成流程

在等待官方優化的同時,我們也可以優化自己的構建流程。

比如使用增量構建、並行構建、緩存機制等。

5. 保持開放心態

技術發展總是充滿變數。

今天砍掉的功能,明天可能以另一種形式迴歸。

保持學習,保持適應,這是程序員的基本素養。

總結:完美往往是優秀的敵人

2007年,蘋果發佈第一代iPhone時,很多功能都不完美。

沒有複製粘貼,沒有多任務,甚至連3G都不支持。

但喬布斯説:"我們不是在做一個完美的產品,而是在做一個足夠好的產品。"

Google這次砍掉宏功能的決定,雖然讓無數開發者失望,但從工程角度來看,這是一個理性的選擇。

技術團隊花了3年時間,投入了大量資源,最終發現這條路走不通。

這時候果斷止損也是需要巨大勇氣的。

我們總是追求技術的完美,希望有一個銀彈能解決所有問題。

但現實是,大部分時候"夠用"比"完美"更重要。

freezed + json_annotation雖然不夠優雅,但它們穩定、可靠、生態成熟。

build_runner雖然慢,但它能解決問題,而且還在持續優化。

在技術的世界裏,我們經常會遇到這樣的選擇:

是追求理論上的完美,還是接受現實中的妥協?

Google這次的決定告訴我們:有時候放棄也是一種智慧。

Dart生態不會因為沒有宏而停滯不前。

相反,它會在現有的基礎上繼續演進,找到更實用的解決方案。

這或許就是工程思維和學術思維的區別。

學術追求完美,工程追求可行。

在技術的世界裏,最大的勇氣不是開始一個項目,而是知道何時該放手。

Google這次的決定,或許正是這種勇氣的體現。

如果看到這裏的同學對客户端開發或者Flutter開發感興趣,歡迎聯繫老劉,我們互相學習。
點擊免費領老劉整理的《Flutter開發手冊》,覆蓋90%應用開發場景。
可以作為Flutter學習的知識地圖。

覆蓋90%開發場景的《Flutter開發手冊》

Add a new 评论

Some HTML is okay.