Feng 代码风格建议
本文档用于沉淀 Feng 代码的推荐书写风格,帮助项目、团队和个人在不改变语言语义的前提下保持代码风格一致。
本文档中的内容均为建议,不是强制规范:
- 不参与语法定义。
- 不改变语义分析、编译器行为或运行时行为。
- 编译器和运行时不得因是否遵循本文档中的建议而改变程序含义。
- 用户可以基于团队协作习惯在本文档建议之上继续细化,也可以在充分理由下偏离本文档建议。
1 总体原则
- 风格建议服务于可读性、一致性和维护成本控制,而不是制造额外语义负担。
- 命名风格应尽量让读者一眼看出符号的大类,例如“契约、类型、成员、局部绑定、常量式全局绑定”。
- 同一文件、同一模块、同一项目内应尽量保持一致,避免同类符号混用多套风格。
2 命名建议
2.1 spec 契约命名
spec定义的契约,无论是类型契约还是函数契约,都建议使用「大驼峰」命名。- 推荐原因: 契约在使用层面通常承担抽象类型或抽象可调用形状的角色,与普通值和成员区分开更直观。
推荐示例:
spec CommitOptions {
var message: i32;
}
spec ValueFormatter(value: i32): string;
2.2 type 类型与成员命名
type定义的类型,建议使用「大驼峰」命名。type的字段、方法、构造函数参数、普通成员名,建议使用「小驼峰」命名。- 这样可以让“类型名”和“成员名”在视觉上自然分层。
推荐示例:
type UserProfile {
let displayName: string;
var loginCount: i32;
func incrementLoginCount(): void {
self.loginCount = self.loginCount + 1;
}
}
2.3 局部 let / var 绑定命名
- 函数、方法、代码块内部的局部
let/var绑定,建议使用「小驼峰」命名。 - 若变量只在很小的局部范围内使用,也建议保持可读性,避免无语义的缩写。
推荐示例:
func commit(message: string): void {
let trimmedMessage = message;
var retryCount = 0;
}
2.4 全局不变绑定命名
- 顶层全局
let绑定中,如果该值承担“类似常量”的角色,建议使用「全大写并以下划线分隔」命名。 - 这里的重点不是“只要是
let就一律全大写”,而是“全局、不可变、并且语义上接近常量”的绑定更适合使用该风格。
推荐示例:
let DEFAULT_PORT = 8080;
let MAX_RETRY_COUNT = 3;
不推荐把普通局部绑定写成同样风格:
func run(): void {
let TEMP_VALUE = 1;
}
3 空行与布局建议
3.1 函数与方法之间的空行
- 同一层级下,多个函数之间建议用一个空行分隔。
- 同一
type内,多个方法之间也建议用一个空行分隔。 - 这样更利于快速扫描声明边界。
推荐示例:
func load(): void {
sync();
}
func save(): void {
flush();
}
type User {
func open(): void {
sync();
}
func close(): void {
flush();
}
}
3.2 函数或方法内部的空行
- 函数或方法内部建议保持紧凑,通常不额外插入空行。
- 只有在确实需要用空行表达逻辑阶段切换时,才建议少量使用。
- 若函数本身很短,优先保持连续阅读体验。
推荐示例:
func commit(message: string): void {
let normalizedMessage = message;
writeLog(normalizedMessage);
flush();
}
4 缩进与花括号建议
4.1 缩进
- 建议统一使用「两空格」作为缩进风格。
- 同一文件内不建议混用不同缩进宽度。
- 同一项目若采用格式化工具,建议其默认输出与本文档保持一致。
推荐示例:
func main(args: string[]) {
if true {
print(args);
}
}
4.2 花括号位置
- 花括号块建议采用“前括号跟在上一行之后”的写法。
- 适用于
func、type、if、else、for、while、try、catch、defer等块结构。
推荐示例:
type User {
func commit(message: i32): i32 {
return message;
}
}
if ready {
run();
} else {
stop();
}
5 一致性建议
- 比单条风格建议更重要的是一致性。
- 一个项目若已经形成稳定风格,新增代码建议优先与现有代码保持一致。
- 若团队后续提供自动格式化器,格式化器输出应视为本文档建议的工程化落地,但本文档本身仍然只是风格建议,不是语言规范。
5.1 类型后缀紧贴建议
- 数组类型后缀
[]建议直接紧贴前一个类型书写,不在类型与方括号之间插入空格。 - 该建议同样适用于泛型类型实例后的数组后缀,例如建议写成
string[]、Map<K, V>[],不建议写成string []、Map<K, V> []。
5.2 泛型角括号紧贴建议
- 泛型参数列表与显式类型实参列表建议直接紧贴前一个类型名、函数名或方法名书写,不在名称与
<之间插入空格,也不在>前插入空格。 - 该建议同样适用于带约束的类型参数列表与嵌套泛型,例如建议写成
Map<K: Hashable<K>, V>、Box<Map<string, int>>,不建议写成Map < K: Hashable<K>, V >、Box<Map<string, int> >。
6 文档注释建议
6.1 公开 API 文档注释
- 对外公开的 API 建议始终提供紧邻声明的
/** */文档注释,尤其是标准库std与官方包中的公开声明。 - 顶层
open type、open spec、open fit、open func以及公开成员方法,都建议提供简洁准确的摘要说明。 - 当参数、返回值、复杂度、零值行为或可见副作用会影响调用方理解时,建议在文档注释中补充
@param、@return或实现说明。 - 公开 API 会显式
throw可捕获的 Feng 异常时,使用@throws说明异常类型或值及触发条件。 - 公开 API 因调用方违反前置条件而调用 runtime panic 时,使用
@panic说明触发条件。@panic不得写成@throws,因为 runtime panic 不是可被catch的 Feng 异常。不需在每个 API 中重复列出内存分配失败、runtime 内部状态损坏等非调用方前置条件。 - 文档注释应描述调用方需要知道的稳定语义,避免把容易过时的内部实现细节写成 API 契约。
7 与其他文档的关系
- 本文档只描述推荐风格,不定义语法和语义。
- 本文档只提供代码风格建议,不定义语法、语义、类型系统、函数规则、生命周期或互操作行为。