news 2026/9/10 12:56:40

Carbon Language 函数返回类型推断:`auto` 返回类型的设计、规则与演进(Proposal 826)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Carbon Language 函数返回类型推断:`auto` 返回类型的设计、规则与演进(Proposal 826)

Carbon Language 函数返回类型推断:auto返回类型的设计、规则与演进(Proposal #826)

【免费下载链接】carbon-langCarbon Language's main repository: documents, design, implementation, and related tools. (NOTE: Carbon Language is experimental; see README)项目地址: https://gitcode.com/GitHub_Trending/ca/carbon-lang

本文基于 Carbon Language 仓库中的正式提案 Proposal #826: Function return type inference,系统讲解 Carbon 如何为函数引入auto返回类型推断:它要解决的问题、核心语法规则(必须显式返回、禁止直接递归、不支持分离的声明与定义)、背后的语言目标权衡,以及被否决的三类替代方案。结合仓库当前的设计文档(docs/design/functions.md、docs/design/type_inference.md)与工具链源码(词法层 toolchain/lex/token_kind.def、语义检查层 toolchain/check/handle_function.cpp),还可以看到该提案中的规则是如何一步步落到语言设计与编译器实现中的。

提案要解决的问题

提案 proposals/p000826-function-return-type-inference.md 开篇提出的核心问题是:是否有更短的方式声明函数?这个问题具体拆解为两个子问题:

  • 是否应该让声明者(declarer)能够要求函数的返回类型从返回值中推断得出?
  • 是否应该提供一种替代的函数语法,在返回类型推断的简单场景下给出更简短的函数声明?

回答这两个问题,就需要引入类型推断机制,并决定它以何种形态嵌入现有的函数声明语法。

背景:既有语法与 C++ 先例

函数声明的既有语法

根据 Proposal #438: Add statement syntax for function declarations,Carbon 批准的函数语句语法是:

fn 标识符 ( 参数列表 ) [ -> 表达式 ] { 语句列表 }

而当时可执行语义(executable semantics)阶段实际支持的语法是:

fn 标识符 ( 参数列表 ) => 表达式

提案指出,C++ 中就有类似的返回类型自动推断机制,而=>的用法又反映了当时为 match 模式匹配(matching)临时讨论的语法。这正是本提案需要在“简洁性”与“语法一致性”之间做取舍的原因。

Lambda 的边界

Lambda 当时也在 Carbon 的讨论中,但预计会采用不同的语法。该提案不试图处理 lambda 语法,只是指出:lambda 语法的决定可能会反过来影响函数声明语法,以维持两者之间的“语法对等性”(syntax parity)。

auto关键字的引入

这是 Carbon 中第一个正式引入auto关键字的提案

  • 提案 #339: var statement 曾在备选方案中提及auto,但并未正式提议该关键字;
  • 不过var x: auto这类用例在 Carbon 中是被预期支持的,因此本提案中的auto可以放在同一语境下考虑;
  • auto的命名和行为总体上与 C++ 保持一致。

在仓库的当前词法实现中,auto已是一个正式的保留关键字,见 toolchain/lex/token_kind.def:

CARBON_KEYWORD_TOKEN(Auto, "auto")

const限定的前车之鉴

C++ 的演进提供了一个重要教训:C++ 最初为 lambda 使用“匹配返回类型”(matching return type),后来切换到基于模板实参推断定义的auto变量规则,后者会丢弃const限定,从而产生微妙的行为差异。提案特别提醒:const在 Carbon 中彼时尚未定义,因此这个坑需要预先留意。

核心提案:-> auto返回类型

提案的主体非常简洁:

fn标识符(参数列表) -> auto {语句列表}

即用新的auto关键字支持自动类型推断,同时附带两条关键限制:

  1. 只允许一条 return 语句。提案明确避免为“返回类型不一致”定义处理规则;
  2. 不支持分离的声明与定义。因为声明必须具有已知的返回类型,auto返回类型下无法先声明、后定义。

这条“单 return”限制在后来的设计文档中得到了落实。docs/design/functions.md 的“Return specification”一节写明:

  • -> auto表示应使用类型推断确定返回类型;
  • 例如fn Echo(val: i64) -> auto { return val; }的返回类型经推断为i64
  • 前向声明(forward declaration)必须有已知返回类型,因此auto不合法
  • 函数必须恰好有一个return语句,该 return 语句的表达式将用于类型推断;
  • auto前可加valrefvar来指定返回的表达类别(expression category)。

关键规则细节

必须显式返回表达式

使用-> auto的函数必须返回一个表达式:隐式返回(函数体末尾自动返回)或裸写return;都是非法的。这一要求与 Carbon 控制流设计中关于“返回空元组”(returning empty tuples) 的约定保持一致——空元组返回只能由省略->子句表达,不能与推断返回类型混用。

在工具链的语义检查层,返回语句的处理集中在 toolchain/check/return.cpp,其中BuildReturnWithNoExpr负责对“无表达式的 return”进行诊断,BuildReturnWithExpr则负责将返回表达式与函数声明的返回形式(return form)做类型转换与一致性检查。auto推断场景正是走“必须有表达式”这条路径。

移除可执行语义中的=>函数语法

提案明确:可执行语义将移除=>函数语法。也就是说,现有写法:

fn Add(x: i32, y: i32) => x + y;

将改写为:

fn Add(x: i32, y: i32) -> auto { return x + y; }

需要说明的是,仓库当前状态中这一移除尚未完全落地。docs/design/functions.md 目前仍将=>描述为“以-> auto推断返回类型”的简写语法(例如fn Add(a: i64, b: i64) => a + b;的返回类型基于表达式a + b推断,且因其返回类型是被推断的,=>定义的函数不能有无定义的前向声明);而在 check 阶段,简洁函数定义的处理入口仍标记为待实现,见 toolchain/check/handle_function.cpp:

auto HandleParseNode(Context& context, Parse::FunctionTerseDefinitionId node_id) -> bool { return context.TODO(node_id, "HandleFunctionTerseDefinition"); }

也就是说,从源码结构看,=>的“terse definition”节点在解析树中已有一席之地,语义处理则处于过渡状态——这与提案中“移除=>函数语法”的长期方向并不矛盾,只是体现了实验性语言实现随提案逐步收敛的过程。

禁止直接递归

直接递归调用会给返回类型推断带来复杂性。提案给出两类示例:

// 在 return 语句中递归。 fn Factorial(x: i32) -> auto { return (if x == 1 then x else x * Factorial(x - 1)); } // 在 return 语句之前,但影响返回类型。 fn Factorial(x: i32) -> auto { var x: auto = (if x == 1 then x else x * Factorial(x - 1)); return x; }

第一种情况中,return表达式的类型依赖Factorial自身的返回类型;第二种情况中,var x: auto的类型同样依赖它。因此提案的结论是:直接递归被拒绝——即返回类型为auto的函数不允许调用自己。

间接递归为什么不需要额外规则

间接递归的典型形态是:

fn ExplicitReturn() -> i32; fn AutoReturn() -> auto { return ExplicitReturn(); } fn ExplicitReturn() -> i32 { return AutoReturn(); }

这是合法的:AutoReturn()的返回类型可以从ExplicitReturn的前向声明算出来是i32

提案进一步论证:由于名称查找(name lookup)的工作方式,间接递归不会给类型推断造成麻烦,理由有二:

  • auto返回类型不允许单独的前向声明(见前文核心规则);
  • 没有单独声明时,名称查找会直接失败。例如下面的代码在return B();处就是名称查找错误:
fn A() -> auto { return B(); } fn B() -> auto { return A(); }

因此,与直接递归不同,间接递归不需要专门的规则

基于 Carbon 语言目标的论证

提案将设计决策锚定在 Carbon 的正式语言目标上(见 docs/project/goals.md):

“易于阅读、理解和编写的代码”

  • 刻意不提供替代函数语法,让用户少学一种需要理解的语法;
  • 作为务实考量,在泛型代码中,auto返回类型往往使某些代码更容易写出来。

“与现有 C++ 代码的互操作及迁移”

  • 有意让auto返回类型的行为与 C++ 的类型推断类似,以降低从 C++ 迁移的门槛。

开放问题

多个 return 语句

提案预期最终应当支持带多个 return 的函数使用auto,但因返回类型可能不一致带来的复杂性,本提案拒绝处理该场景,留给后续提案。

值得注意的是,仓库中的设计文档已经朝这个方向演进:docs/design/README.md 在“Common type”一节中写道,带auto返回类型的函数,其推断出的返回类型是其各个return语句表达式的公共类型(common type),该公共类型由CommonTypeWith接口的实现给出:

// A 和 B 的公共类型是 C。 impl A as CommonTypeWith(B) where .Result = C { }

且公共类型要求两个类型都能隐式转换到它。这表明“多 return 的auto推断”这一开放问题正在以公共类型机制的形态被逐步解决。

const限定

如背景部分所述,C++ 在const限定上经历过变化。提案认为应当选择一个长期可行的方案,这很可能要等到模板实参推断(deduction for templates)的规则被处理时再重新审视。

被否决的替代方案

仅当参数为泛型时才允许auto返回类型

动机:auto返回类型对可读性可能是负资产——读者必须读函数体才能确定返回类型。一种限制方案是:只有当参与推断的参数是泛型(generic)时才允许auto

  • 优点:限制auto对可读性的影响——返回类型显然可确定的地方不许用auto(那些地方本就容易手写返回类型);只有在泛型参数使返回类型难以书写时才允许。
  • 缺点:增加auto使用规则集;破坏 C++ 兼容性

最终决定是允许auto用于更多场景,主要理由就是 C++ 兼容性。这一备选在 docs/design/functions.md 的参考资料列表中仍被引用。

提供简洁返回类型推断的替代函数语法

即可执行语义中现有的:

fn Add(x: i32, y: i32) => x + y;
  • 优点:对短函数提供更简练的定义方式;=>与 match 的暂定语法呼应。
  • 缺点
    • 为等价行为引入额外语法;
    • 与 lambda 用例重叠,但 lambda 最终很可能长成不同的样子——不应假设两者会收敛。Lambda 语法甚至可能走得更激进、更简短,而这种简写放在具名函数声明中未必合理;
    • 占用=>这个记号的其他用途。如果=>主要是在替代-> auto(类似假设 Carbon 采纳 Rust 风格的块表达式返回值),那么它作为额外记号的收益很有限。

提案的结论是:现阶段不加入推断导向的替代函数语法。虽然它与 match 的暂定语法一致,但函数语法的割裂程度较大,此处适用“one way”原则——即尽量让每一种行为只有一种写法。如果将来要加入替代函数语法,应当与 lambda 提案同步推进,以保证语法一致。

仓库现状佐证了这一“与 lambda 同步”的思路:lambda 提案 p003848 中大量使用let lambda: auto = fn => T.Make();这类写法,并明确将fn => 表达式定义为“等价于-> auto { return 表达式; }”,让 lambda 与函数声明共享同一套auto推断语义。

允许分离的声明与定义

返回类型必须能从声明处确定,因此返回auto的函数其声明与定义不能显著分离——调用者必须能看到定义。一种折中方案是:只要调用者能同时看到声明和定义,就允许auto搭配分离的声明/定义。

该方案下,这个例子合法,因为CallAdd能看到Add的定义:

fn Add(x: i32, y: i32) -> auto; fn Add(x: i32, y: i32) -> auto { return x + y; } fn CallAdd() -> i32 { return Add(1, 2); }

而这个例子非法CallAdd只能看到Add的声明(即使定义在同一文件里),缺少定义就无法确定返回类型:

fn Add(x: i32, y: i32) -> auto; fn CallAdd() -> i32 { return Add(1, 2); } fn Add(x: i32, y: i32) -> auto { return x + y; }
  • 优点:可以在文件中把简短声明聚集在前、定义放后面;类声明中尤其常见(提供声明、在类外定义以免打断类 API 的呈现)。不过若auto返回类型只推荐用于短函数,短函数本就可以内联,这一优势有限。
  • 缺点:无法用于打破调用循环——这正是分离声明/定义的常见用途。单独声明在定义给出之前依然不可被调用,这对人类读者尤其容易造成困惑。

最终决定:不支持auto返回类型的分离声明与定义,理由是其效用有限。这一决定与当前设计文档保持一致:docs/design/functions.md 明确写着“前向声明必须有已知返回类型,因此auto不合法”。

提案的落地情况:从设计文档到工具链

综合仓库现状,可以看到提案 #826 的内容在三层面上的落点:

  1. 词法层auto已登记为关键字(toolchain/lex/token_kind.def),这是所有后续语义的前提。
  2. 设计层:docs/design/functions.md 的“Return specification”一节完整吸收了提案的核心规则——-> auto触发类型推断、恰好一条return、前向声明禁用autoauto可被val/ref/var限定;docs/design/type_inference.md 则声明“目前类型推断支持函数返回类型”,并指出当前推断规则很简单:给定产生值的表达式,推断出的类型就是该表达式的精确类型。
  3. 实现层:函数签名(含返回形式)的构建集中在 toolchain/check/handle_function.cpp 的BuildFunctionDecl中,它统一处理声明与定义两种语法形态,并把return_type_inst_idreturn_form_inst_id等字段存入SemIR::Function;返回语句的语义检查(含对“无表达式 return”“声明了返回类型却缺少 return”的诊断)位于 toolchain/check/return.cpp 与 toolchain/check/handle_function.cpp(函数体可达但未 return 时触发MissingReturnStatement诊断)。

小结

提案 p000826 为 Carbon 引入了fn ... -> auto { ... }这一返回类型推断机制,其设计可以概括为四条硬规则加三项取舍:

  • 必须显式return 表达式,不支持隐式返回;
  • 函数恰好一条 return 语句,避免多返回类型不一致的复杂性;
  • 禁止直接递归,间接递归靠名称查找自然排除;
  • 不允许auto返回类型的前向声明,声明与定义不能分离;
  • 不为简洁性引入=>等替代函数语法(one way 原则、与 lambda 语法解耦);
  • 不限制auto仅用于泛型参数,优先保持与 C++ 的推断语义一致,服务于 C++ 迁移目标。

从仓库当前状态看,auto返回类型已写入正式设计文档并在词法与语义检查中持续落地,而提案遗留的两个开放问题——多 return 的公共类型推断与const限定——正分别通过CommonTypeWith公共类型机制和模板推断规则的后续工作被推进。

【免费下载链接】carbon-langCarbon Language's main repository: documents, design, implementation, and related tools. (NOTE: Carbon Language is experimental; see README)项目地址: https://gitcode.com/GitHub_Trending/ca/carbon-lang

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 12:54:11

QT5摄像头开发:预览、截图与保存的完整管线

简介:一份QT5摄像头调用与截图保存项目资源,面向需要用Qt Widgets开发多媒体或监控应用的开发者。资源以QtCamerTestOfLT完整工程为主线,涵盖项目配置、界面设计与功能实现等完整源码结构,聚焦QCamera、QCameraViewfinder、QCamer…

作者头像 李华
网站建设 2026/9/10 12:52:49

Ubuntu终端Python开发中文输入法配置指南

1. 问题背景与现象描述在Ubuntu系统下使用nano、vim等终端编辑器编写Python代码时,许多开发者会遇到无法切换中文输入法的困扰。这个问题的典型表现为:在终端编辑器内按常规快捷键切换输入法时无反应,或虽然状态栏显示已切换为中文输入法&…

作者头像 李华
网站建设 2026/9/10 12:51:40

GRACE水储量反演:从球谐系数到等效水高的Matlab实现

简介:面向GRACE卫星重力数据应用研究的一套Matlab代码,聚焦陆地水储量变化反演,适合地球物理、水文学及遥感方向的师生和工程师,用于解决从重力场位系数出发解算区域水储量变化的关键问题。压缩包共10个文件、约655KB,…

作者头像 李华