F# 编码风格¶
本文件使用 F# 特定内容扩展 common/coding-style.md。
标准¶
- 遵循标准 F# 约定,利用类型系统确保准确性
- 默认优先使用不可变性。仅在性能原因下使用
mutable - 保持模块聚焦和高内聚
类型与模型¶
- 领域建模优先使用判别联合而非类层次结构
- 对具有命名字段的数据使用记录
- 对基本类型使用单案例联合作为类型安全包装
- 除非需要互操作或可变状态,否则避免使用类
type EmailAddress = EmailAddress of string
type OrderStatus =
| Pending
| Confirmed of confirmedAt: DateTimeOffset
| Shipped of trackingNumber: string
| Cancelled of reason: string
type Order =
{ Id: Guid
CustomerId: string
Status: OrderStatus
Items: OrderItem list }
不可变性¶
- 记录默认不可变。使用
with表达式进行更新 - 优先使用
list、map、set而非可变集合 - 在领域逻辑中避免使用
ref单元格和可变字段
函数式风格¶
- 优先使用小而可组合的函数而非大型方法
- 使用管道运算符
|>构建可读的数据管道 - 优先使用模式匹配而非 if/else 链
- 使用
Option代替 null。对可能失败的操作使用Result
let processOrder order =
order
|> validateItems
|> Result.bind calculateTotal
|> Result.map applyDiscount
|> Result.mapError OrderError
异步与错误处理¶
- 与 .NET 异步 API 互操作时使用
task { } - 对 F# 原生异步工作流使用
async { } - 通过公共异步 API 传播
CancellationToken - 对预期错误优先使用
Result和铁路导向编程而非异常
let loadOrderAsync (orderId: Guid) (ct: CancellationToken) =
task {
let! order = repository.FindAsync(orderId, ct)
return
order
|> Option.defaultWith (fun () ->
failwith $"Order {orderId} was not found.")
}
格式¶
- 使用
fantomas进行自动格式化 - 优先使用有意义的空白。避免不必要的括号
- 删除未使用的
open声明
open 声明顺序¶
open 语句用空行分成四个部分进行分组,每个部分内按字典顺序排列:
System.*Microsoft.*- 第三方命名空间
- 第一方 / 项目命名空间
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 ev/ECC