类型声明语法

Lobsters Hottest 新闻

摘要

这篇文章探讨了C语言的类型声明语法在现代编程语言中的遗留问题,并比较了Go和Rust中使用的替代语法。

<p><a href="https://lobste.rs/s/qphopj/type_declaration_syntax">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/09/16 19:29

# 类型声明语法 - citrons.xyz 原文:https://citrons.xyz/journal/2026-09-09 当今大多数常用编程语言都在不同程度上受到 C 语言的影响。不过它们大多并未沿用 C 的类型语法。C 的类型语法可能相当难懂——虽然不至于*那么*糟(https://citrons.xyz/why-c-type-syntax),但确实不值得效仿。最大的问题出现在用户自定义类型,特别是使用 `typedef` 时。即使没有这个特性,结构体和联合体依然可以定义,但每次使用都必须加上 `struct` 或 `union` 关键字。你不能声明变量 `my_struct a`,而必须写成 `struct my_struct a`。但有了 `typedef` 后情况就不同了,这导致 C 的文法不再是上下文无关文法。例如要解析语句 `foo (*x);`,就必须先判断 `foo` 是否为类型。这一点极不理想。 有些编程语言直接照搬 C 的声明语法(例如 Java、C#、D)。这种做法本身并不比 C 本身更令人困惑,但极易导致严重的理解混乱——因为类型名称常常开始被当作其自身表达式的一部分(而在 C 中这显然不成立)。无论采用哪种风格都可以接受,但将两种风格混用则极其不明智。这才是导致类型语法晦涩难懂的真正原因。以下两种写法在 Java 中都是有效的: ``` int myArray[]; int[] myArray; ``` C++ 并不真实。我在不同语言中见过多种类型声明的替代语法。所有这些例子都将类型视为独立自包含的表达式。 ## `标识符 类型` Go 语言采用了这种语法——它是我最喜爱的语言之一。由于 Go 可以看作是 C 的真正续作(作为应用层语言使用),因此这种设计可视作对 C 理念的迭代。先写标识符,再写类型。它有些类似 C 的倒序写法。这种设计很巧妙,因为类型可以是任意复合表达式,而标识符仅是单个词元。 指针类型表达式以 `*` 为前缀。数组也采用 `[]` 前缀而非后缀。这可能让习惯 C 的程序员感到奇怪,但好处在于能明确区分“指针数组”和“数组指针”,消除歧义。 这种语法在 Go 中工作良好,但如果你正在设计一门语言,需要注意:如果不谨慎设计其他语言特性,可能会带来解析困难。其本质是两个表达式并列放置。虽然一个是标识符、另一个是类型表达式,但当类型表达式出现在其他类型表达式可能出现的位置时,就会产生歧义。必须确保其他语法中不存在此类表达式并列的可能。 ## `标识符 : 类型` ML 语言采用了这种语法。值得注意的是,Rust 也采用了这种语法——它就像 ML 遇上了 C++(虚构的)。这种语法相当优雅。这些语言的类型系统与 C 有着天壤之别,其范围之广足以构成完整的语言,类似内嵌的 Prolog。它们重点强调代数数据类型,像指针这样底层的概念并不常用。Rust 采用类似 C++ 的引用,通过在类型前添加 `&` 前缀来表示。 目前单冒号类型标注非常流行,支持这种语法的语言在类型系统类型上各不相同。以我所见,包括 Zig、Swift 和 Hare。许多原本仅支持动态类型的语言都扩展了类型标注功能,可能也会采用这种冒号语法:TypeScript(拥有非常复杂的类型系统)以及 Python(现在具有...似乎毫无作用的类型标注?!)。 有趣的是 Python 也使用单冒号实现此功能,因为它还使用冒号表示另一个完全不同的关键语法结构。这将是不采用这种语法的主要原因——如果你希望将这个历史悠久且功能多样的冒号用于其他地方,特别是当你的语言类似 Hare(类型声明与强制转换语法统一)时。人们可能写 `let a = b: u8;`(将 `b` 转换为 `u8`),也可能写 `let b: u8 = 128;`。这显然排除了在表达式中使用 `:` 表示其他含义(例如 C 风格三元运算符)的可能性。 书写风格上可能写成 `标识符 : 类型` 或 `标识符: 类型`,具体取决于语言和风格。 ## `标识符 :: 类型` Haskell 采用了这种语法。Haskell 受 ML 影响,但不使用单冒号——因为它用单冒号表示 cons 运算符。严格来说,我认为它*可以*使用单冒号而不产生歧义,因为每个类型声明都是独立语句。但若将同一词元用于两种目的可能会引起混淆。

相似文章

解析C语言中类型推断声明之险

Lobsters Hottest

这篇博文探讨了C23中涉及`auto`作为类型推断说明符或存储类说明符的解析歧义,展示了当`x`是typedef时,GCC和Clang在解析如`auto x = 67;`这样的声明上的分歧,以及属性如何使情况复杂化。

Stroustrup法则(2024)

Hacker News Top

Bjarne Stroustrup的法则指出:对于新特性,程序员更偏好显式语法,但一旦该特性被确立,他们就更倾向于简洁表示法。本文探讨了 Rust 和 Python 中的示例,并讨论了这对语言设计和教学的影响。

编程语言中的一些好点子

Hacker News Top

本文讨论了三种编程语言特性:用于在Crystal和TypeScript等静态语言中实现动态感觉的流类型、用于确保Rust内存安全的借用检查,以及用于D语言中不变性检查的契约编程。

Go 泛型中的 GC shape stenciling

Hacker News Top

深入解释 Go 编译器如何使用 GC shape stenciling 实现泛型,并与 Rust 的 full monomorphization 和 Java 的 type erasure 进行比较。

关于C数组类型语义的讨论

Lobsters Hottest

本文解释了C数组类型的令人困惑的行为,包括它们退化为指针、sizeof和函数参数等例外情况,并将其与函数类型进行比较,提出了一种数组和指针严格分离的心理模型。