本文永久链接https://tonybai.com/2026/09/04/rust-function-overloading-experiment-nightly-splat

大家好,我是Tony Bai。

【导读】

八月十九日,Rust语言团队在Inside Rust官方博客上悄悄放出一枚“重磅炸弹”——函数重载(function overloading)实验正式登陆Nightly版本。这是Rust历史上第一次由官方语言团队牵头、系统性地探索“重载”这一在C++、Java、Python等语言中司空见惯,却始终被Rust拒之门外的特性。

背后的推手,是Rust基金会的Rust-C++互操作计划(Interop Initiative),其资金支持方正是谷歌。这场实验的终极目标只有一个:让Rust调用C++重载函数时,不再需要人工改名、不再需要维护者小心翼翼地绕开重载陷阱,真正实现“丝滑”互操作。

这一次,Rust埋下的种子名叫splat——一个还带着“占位符”气质的临时语法,却可能是打开Rust与C++边界的一把关键钥匙。

【文章要点】

  • Rust官方语言团队联合Rust基金会,正式启动函数重载语言实验,目标是解决Rust调用C++重载函数时的“命名地狱”问题;
  • 实验以#[rustc_splat]属性为起点,允许被重载的函数像普通函数一样被调用,例如hypot(2.0, 3.0, 6.0),而不必再套一层元组;
  • 该特性已于2026年7月31日起进入Nightly编译器,目前仍是“不完整特性”,可能随时更改或移除;
  • 文章将结合官方示例,拆解splat的工作原理、当前的能力边界,以及Rust团队为“重载”划下的四条设计公理;
  • 展望“闪光的未来”(Shiny Future):一个#[overload]属性也许会让重载调用彻底“消失于无形”。


Rust语言团队官宣:重载实验来了

八月十九日,Rust核心贡献者teor代表Rust语言团队(Language Team),在Inside Rust官方博客上正式发文,宣布函数重载语言实验已经进入Nightly编译器,向编译器与互操作工具开发者开放试用。

这项工作的背景,是Rust基金会主导的Rust-C++互操作计划(Rust-C++ Interop Initiative)。该计划由谷歌提供资金与支持,目标是打通Rust与C++两大语言生态之间的"任督二脉"。而函数重载,正是横亘在这条路上最顽固的一块石头。

对于长期使用Rust的开发者而言,“重载”两个字或许有些陌生——因为Rust从设计之初,就刻意与这个特性保持距离。而这一次,官方终于决定正面回应它。

老问题:Rust为什么一直“没有”函数重载

在C++、Java这类语言里,函数重载几乎是家常便饭:同一个函数名,可以根据参数个数和类型的不同,对应到完全不同的实现。比如C++标准库里的std::hypot,既可以接收两个参数计算二维距离,也可以接收三个参数计算三维距离。

但Rust的哲学不太一样。Rust依赖trait系统实现“泛型分派”,理论上也能做到类似重载的效果,但代价是牺牲了调用语法的自然性

举个例子,如果想让MyType同时支持foo()foo(1, 2)两种调用方式,在纯trait方案下,你必须把参数打包成元组,写成这样:

impl Foo<()> for MyType {
    type Return = i32;
    fn foo(&self, _args: ()) -> i32 { 42 }
}
impl Foo<(i32, i32)> for MyType {
    type Return = i32;
    fn foo(&self, args: (i32, i32)) -> i32 {
        args.0 + args.1
    }
}

x.foo(());
x.foo((1, 2));

调用方不得不多套一层括号,写出x.foo(())这种略显别扭的代码。这在纯Rust项目里或许只是“审美问题”,但一旦涉及C++互操作,问题就被放大了:C++库每新增一个重载,Rust绑定生成工具就必须手动给它起一个新名字,比如func1func2……这意味着C++那边看起来毫无痛感的一次API迭代,到了Rust这边就可能是一次破坏性变更。

更棘手的是,Rust的trait一致性(coherence)规则比C++严格得多。C++里两个“理论上会冲突、但实际类型不会重叠”的重载可以和平共处,而Rust编译器在trait实现阶段就会直接拒绝编译,哪怕冲突只存在于理论层面。这也是为什么,Rust团队在项目目标文档中明确写道:这次实验并不打算完全复刻C++的重载解析规则,因为不同语言的重载规则本就互相冲突,勉强对齐反而会让Rust变得不像Rust。

现状:stable Rust里的“伪重载”

其实,稳定版Rust并非完全没有重载能力,只是形态比较“隐晦”,主要体现在两个地方:

第一,元组加trait的“重载”。 正如上文提到的hypot((2.0, 3.0, 6.0))写法,Rust允许通过不同的元组类型实现参数级别的重载,只是调用时必须把所有参数打包进一个元组参数里。

第二,运算符重载。 这是Rust开发者更熟悉的场景:通过实现AddNeg等标准库trait,可以让自定义类型支持+-等内置运算符。这本质上也是一种“重载”,只不过限定在运算符这一特殊场景里。

这两种方式共同的问题是:它们都不够通用,也不够自然。而这正是splat实验想要解决的核心矛盾。

splat登场:#[rustc_splat]到底做了什么

为了避免陷入“起名字”这种历来最耗时的社区争论(Rust团队戏称这是“bikeshedding”),实验的第一阶段刻意选择了一个朴素、临时的语法:#[rustc_splat]属性。这个名字借鉴了Rust历史上yeet关键字实验的传统——先用一个“占位符”名字把机制跑通,语法命名留到后面再讨论。

splat要解决的问题很直接:让重载函数可以像普通函数一样被调用,参数各自独立传入,而不必打包成元组

对比一下:

  • 旧写法(stable Rust):hypot((2.0, 3.0, 6.0))
  • 新写法(splat实验):hypot(2.0, 3.0, 6.0)

少了一层括号,看起来是个很小的改动,但这一层括号,恰恰是Rust调用C++重载函数时最大的“违和感”来源。

需要强调的是,splat只是改变了调用的表面语法,类型推导和类型检查的底层机制,依然和stable Rust下的重载完全一致。换句话说,splat并没有引入新的类型系统能力,它做的事情更像是“语法脱糖”——把开发者从元组包装的繁琐中解放出来。

目前,这项工作已经从2026年7月31日起进入Nightly编译器。Outreachy实习生Ajay Singh也在同步开发一个配套宏,进一步降低splat重载的使用门槛,相关代码已经开源在rust-foundation/overloading-macros仓库中。

实战拆解:用splat调用C++重载的hypot函数

官方博客给出了一个非常直观的示例:用splat特性,从Rust里调用C++标准库中重载的std::hypot函数(计算欧几里得距离)。

#![feature(splat, tuple_trait)]
#![expect(incomplete_features)]

use cpp::cpp;
use std::{ffi::c_double, marker::Tuple};

cpp! {{ #include <cmath> }}

/// 重载版 C++ hypot 函数的参数集合
trait HypotArgs: Tuple {
    type Output;
    fn call_hypot(self) -> Self::Output;
}

/// 用splat调用重载版 C++ std::hypot 函数
fn hypot<Args: HypotArgs>(#[rustc_splat] args: Args) -> <Args as HypotArgs>::Output {
    args.call_hypot()
}

/// 2 参数版本的 hypot 重载
impl HypotArgs for (c_double, c_double) {
    type Output = c_double;
    fn call_hypot(self) -> c_double {
        let (x, y) = self;
        unsafe {
            cpp!([x as "double", y as "double"] -> c_double as "double" {
                return std::hypot(x, y);
            })
        }
    }
}

/// 3 参数版本的 hypot 重载
impl HypotArgs for (c_double, c_double, c_double) {
    type Output = c_double;
    fn call_hypot(self) -> c_double {
        let (x, y, z) = self;
        unsafe {
            cpp!([x as "double", y as "double", z as "double"] -> c_double as "double" {
                return std::hypot(x, y, z);
            })
        }
    }
}

fn main() {
    println!("|(3, 4)|    = {}", hypot(3.0, 4.0));
    println!("|(2, 3, 6)| = {}", hypot(2.0, 3.0, 6.0));
}

拆开来看,这段代码做了三件事:

  1. 定义一个“参数集合”traitHypotArgs),约束它必须是一个元组(Tuple),并规定每种参数组合都要提供一个call_hypot方法;
  2. hypot函数的参数标注#[rustc_splat],告诉编译器:这个参数虽然类型是元组,但调用时请允许“打散”传入;
  3. 为每一种重载组合分别实现HypotArgs,2个参数对应一种实现,3个参数对应另一种实现,各自内部再通过cpp!宏调用真正的C++函数。

最终,调用方拿到的体验就是hypot(3.0, 4.0)hypot(2.0, 3.0, 6.0)——和写普通Rust函数几乎没有区别,C++那头的重载逻辑被完整地“透传”了过来。

这里用到的cppcrate,是一个允许在Rust文件里内联C++代码的工具。官方也提供了完整可运行的示例仓库(rustfoundation/overloading-examples),以及可以直接在Rust Playground里运行的纯Rust最小示例,方便感兴趣的开发者动手一试。

图解:splat的调用解析流程

为了更直观地理解splat做了什么,我们可以用下面这张图,对比“旧写法”与“新写法”在调用链路上的差异:

可以看到,splat并没有改变类型匹配与分派这一核心逻辑(两条链路的第三步完全一样),它改变的只是参数如何从调用方传递到trait实现这一步。这也印证了官方博客反复强调的一句话:“类型推导和类型检查,仍然与stable Rust下的重载完全一致”

再看一张图,理解整个重载体系在Rust发展路线上所处的位置:

从这张时间线可以看出,splat只是Rust重载版图上的中间站,而非终点。

边界与限制:当前还不能做什么

作为一个不满周岁的实验特性,splat目前依然“毛边丛生”:

  • 仅限Nightly,且随时可能变更或撤销。这是Rust语言实验的一贯规矩:没有RFC,没有稳定性承诺,纯粹用来验证想法。
  • 语法本身不够优雅。团队在博客中直言,#[rustc_splat]只是权宜之计,真正的语法糖还在设计阶段。
  • rustdoc展示支持刚刚合并(8月12日),目前splat参数在文档中会显示为省略号“…”,而不是参数名,这一展示格式本身也是不稳定的,可能随时调整。
  • 函数指针的splat支持也是近期才合并,如果遇到内部编译器错误(ICE),官方建议升级到最新Nightly版本。
  • 标准库层面,一项使用splat实现变参smallest/greatest函数的实验也在推进中,有望不久后登陆Nightly。

团队坦言,随着实验推进,会不断有新的bug和边界情况被发现(过去几个月已经有若干问题被标记为F-splat标签),一部分重载相关的功能目前也被明确排除在实验范围之外。如果开发者在试用中遇到问题,官方给出的反馈渠道是Zulip的#t-lang/interop频道。

四条设计公理:Rust想要什么样的重载

无论splat语法最终如何演变,Rust团队为“重载”这件事划出了四条不会动摇的设计公理:

设计公理 含义
保持Rust的“温和” 重载应当是在现有语言语义上的自然延伸,而不是另起炉灶的替代方案
让调用重载的FFI函数变得简单 这是整个实验最直接的现实目标
维护外语(C++等)一方的可维护性 C++库新增或删除一个重载,不应该给Rust调用方带来比C++调用方更大的破坏性
选出大多数开发者都会预期的那个重载 避免“调用能编译,但选中的却不是你以为的那个函数”这种意外

值得一提的是,官方特别强调:这不是要在Rust里复刻C++的重载解析规则。Rust可能需要同时兼容多种语言的重载习惯,而不同语言的规则本身就可能互相矛盾——比如C++的实参依赖查找(ADL),Rust团队明确表示不会照搬。

团队的底线只有一句话:每一个C++函数都应该“可以被调用”,但不代表它必须以和C++完全相同的方式被调用——必要时,要求开发者显式转换类型或添加消歧标记,是完全可以接受的。

展望未来:#[overload]与"闪光的未来"

博客的结尾,Rust团队描绘了一幅更长远的图景——他们称之为“闪光的未来”(Shiny Future):

#[overload]
impl f64 {
    /// 返回到原点的二维距离
    fn hypot(self, y: f64) -> f64 {  }

    /// 返回到原点的三维距离
    fn hypot(self, y: f64, z: f64) -> f64 {  }
}

在这个设想中,开发者只需要一个#[overload]属性,剩下的trait、元组、#[rustc_splat]统统由编译器在幕后自动处理——真正做到“调用重载的外部函数,就像调用普通Rust函数一样自然”。考虑到这项工作的出发点是互操作,团队目前倾向于先把重载能力限制在extern代码块内,至于是否要把它扩展到原生Rust代码里,则可能是一个时间线拉得更长、甚至永远不会发生的独立议题。

但团队也坦诚地表示:现在谈论最终形态还为时尚早。splat实验的真正使命,是帮助团队摸清楚Rust现有类型系统的能力边界、验证它能覆盖多少种典型的外语重载场景、打磨出足够清晰的诊断信息,并为下一阶段的设计工作找出真正的难点所在。至于最终的语法长什么样——用团队自己的话说,“起名字很难,这一点每个搞过函数重载的人都深有体会”。

小结

这次实验的价值,或许不在于#[rustc_splat]这个语法本身能走多远,而在于它标志着Rust第一次把“函数重载”当作一个值得认真对待的语言级问题,而不再是靠trait系统“曲线救国”的边缘用法。对于长期被C++互操作的重载难题所困扰的绑定生成工具(Crubit、cxx、autocxx、bindgen等)而言,这可能是几年来最值得关注的信号之一。

如果你是编译器开发者、互操作工具作者,或者只是单纯对Rust类型系统的边界感兴趣,不妨在Nightly上跑一跑官方给出的示例,或者去Rust Playground里直接体验:

  • 完整可运行示例仓库:rustfoundation/overloading-examples
  • 配套的ergonomics宏:rust-foundation/overloading-macros
  • 反馈渠道:Rust Zulip的#t-lang/interop频道

Rust与C++之间那道运行了十几年的“高墙”,或许正在被一点点凿开缺口。

参考资料:

Rust官方Inside Rust博客《Rust Function Overloading - Call for Experimentation》(2026年8月19日)及Rust Project Goals相关文档。https://blog.rust-lang.org/inside-rust/2026/08/19/overloading-experiment/


还在为写 Agent 框架频频死循环、上下文爆炸而束手无策?我的新专栏 从0 开始构建 Agent Harness 将带你:

  • 抛弃臃肿框架,回归“驾驭工程 (Harness Engineering)”的第一性原理
  • 用 Go 语言手写 ReAct 循环、并发拦截与上下文压缩引擎等,复刻极简OpenClaw
  • 构建坚不可摧的 Safety Middleware 与飞书人工审批防线
  • 在底层实现 Token 成本审计、链路追踪与自动化跑分评估
  • 从“调包侠”进化为掌控大模型边界的“AI 操作系统架构师”

扫描下方二维码,开启从 0 开始构建Agent Harness 的实战之旅。


「Go & AI 精进营」已全面升级为「Go, Rust & AI 精进营」知识星球,快来加入星球,开启你的技术跃迁之旅吧!

我们致力于打造一个高品质的 现代系统级开发(Go / Rust)前沿 Agentic AI 工程实践 平台。在这里,你将获得:

  • 体系化 Go 核心进阶内容: 深入「Go原理课」、「Go进阶课」、「Go避坑课」等独家深度专栏,夯实你的 Go 语言内功。
  • 硬核 Rust 专项实战赋能: 同步解锁全年 54 讲独家专栏「事不过三:Rust 系统级入门实战课」,通过 4 个里程碑项目(命令行工具、KV引擎、多线程Web服务、异步Redis),带你彻底攻克所有权与并发高山,拿下 Rust 核心壁垒。
  • 前沿 Agentic AI 落地实践: 紧跟时代步伐,系统学习「Agent开发实战课」、「Agentic软件工程课」、「Claude Code开发工作流实战」、「Harness工程设计」等,掌握 AI 时代的系统架构新技能。
  • 星主 Tony Bai 亲自答疑: 遇到疑难杂症?星主第一时间为你深度解析,扫清 Go、Rust 与 AI 实践中的学习与工程障碍。
  • 高活跃 Gopher & Rustacean 交流圈: 与众多优秀的技术极客探讨系统设计、分享前沿心得、碰撞思想火花。
  • 独家资源与专栏首发: 博客深度长文、专栏教程更新、精选技术资源,星球会员第一时间触达,加入星球即可免费阅读全套进阶专栏!

衷心希望「Go, Rust & AI 精进营」能成为你拓宽技术边界、持续精进与交流的温暖港湾。让我们在此相聚,享受代码与工程之美以及技术精进的快乐!欢迎你的加入!


商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。