哈喽,我是老刘
就在刚刚结束的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中,你只需要写:
c
#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中,如果有了宏,我们可能只需要:
dart
@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团队承诺会推出专门针对数据类的语言特性。
什么意思?
就是不用宏,也能优雅地处理数据序列化、比较、拷贝这些常见操作。
比如,未来可能会有这样的语法:
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给现有的类添加方法:
dart
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学习的知识地图。
------ laoliu_dev