Sorbet 入门:给 Ruby 加上渐进式类型检查

Sorbet 是 Stripe 开源的 Ruby 渐进类型检查器,从零注解起步逐步收紧。本文讲解 sig 注解语法、严格级别体系、可选与联合类型、流敏感收窄与项目落地路径。

最佳实践
红宝石与应用开发工作台插画

Sorbet 通过在方法前写 sig { params(x: Integer).returns(String) } 注解类型,在开发期(编辑器实时)和 CI 中静态检查类型错误。渐进式设计允许老项目从 typed: false 起步,按文件逐步提升严格级别,百万行级代码库也能平滑接入。

Sorbet 的渐进哲学

与"要么全部类型化要么没有"的方案不同,Sorbet 接受现实:大型 Ruby 项目不可能一夜加完类型。它的策略是按文件分级——从不检查到最严格共五档,团队按节奏推进,类型保障随时间单调增强。Stripe 用它在数百万行代码上运行多年,验证了这条路线的可行性。

安装与初始化

gem install sorbet sorbet-runtime
# 项目初始化(生成 sorbet/ 目录与 RBI 文件)
bundle exec srb init

初始化会扫描项目与依赖 gem,生成 RBI(Ruby Interface)签名文件——Rails 的动态方法靠 tapioca gem 生成 RBI 补齐。

sig 注解与严格级别

# typed: true
extend T::Sig

sig { params(name: String, age: Integer).returns(String) }
def greet(name, age)
  "#{name},#{age + 1} 岁生日快乐"
end

文件头的 magic comment 决定检查强度:

  • # typed: false:不检查(存量代码起点)
  • # typed: true:检查已注解的方法调用、基本类型错误
  • # typed: strict:所有方法和实例变量必须有注解
  • # typed: strong:全部代码可静态推导(新代码的理想目标)

srb tc 命令执行全项目检查,CI 中运行拦截类型回归。

类型系统速览

sig { params(user: T.nilable(User)).returns(T::Array[String]) }   # 可空、数组
sig { params(id: T.any(Integer, String)).void }                    # 联合类型
sig { params(opts: T::Hash[Symbol, T.untyped]).void }              # 哈希
T.let(0, Integer)                                                  # 局部变量标注
  • T.nilable(X):X 或 nil;
  • T.any(A, B):联合类型;
  • T.untyped:放弃检查(渐进期的逃生舱,逐步消除)。

流敏感类型收窄

Sorbet 理解控制流:

def display(user)
  return '游客' if user.nil?
  user.name   # 此处 user 自动收窄为 User,不再报 nil 警告
end

判空之后、case 分支内、is_a? 检查之后,类型自动收窄——写法和普通 Ruby 一致,检查器跟得上你的思路。

与 RBS 的分工想象

Sorbet 注解写在源码里(sig 块),带运行时校验(开发环境参数错误立即抛异常);RBS 类型写在独立文件,纯静态。详细对比见本系列《Sorbet 和 RBS 怎么选》。大型 Rails 项目 Sorbet 生态(tapioca、sorbet-rails)目前更成熟。

常见问题(FAQ)

Q:Sorbet 会拖慢运行速度吗?

静态检查(srb tc)不影响运行;运行时校验(sig 的运行时部分)在测试环境开启、生产环境可配置关闭或采样——性能开销可控,且 Sorbet 编译器本身是 Rust 级速度,大项目检查以秒计。

Q:Rails 的动态方法(find_by_xxx)怎么通过检查?

用 tapioca 生成 RBI 文件描述这些动态方法:bin/tapioca dsl 生成模型相关 RBI,bin/tapioca gem 生成 gem 的 RBI,提交进仓库即可。

Q:团队推进 Sorbet 的正确节奏?

第一阶段全项目 typed: false 跑通 CI;第二阶段新文件默认 typed: true;第三阶段核心领域模型升 strict;配合 spoom bump 工具批量提升文件级别。切忌运动式强推——类型系统是工具不是 KPI。


参考文档

本文依据公开文档整理,示例需按项目依赖版本验证;不将文档中的性能描述视为本项目实测结果。

延伸阅读

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台