Sorbet为何不检查数组类型参数的运行时类型?
Sorbet数组参数运行时类型检查不触发的原因分析
基础代码示例
require 'bundler/inline' gemfile do source 'https://rubygems.org' gem 'sorbet-runtime' end require 'sorbet-runtime' class Numbers extend T::Sig sig { params(a: Integer, b: Integer).returns(Integer) } def sum_of_two(a, b) a + b end sig { params(values: T::Array[Integer]).returns(Integer) } def sum_of_array(values) values.sum end end
测试代码及现象
Numbers.new.sum_of_two(1, 2) # => 因实际参数均为整数,无报错 # Numbers.new.sum_of_two(1.0, 2) # => 因其中一个参数为Float,触发错误 Numbers.new.sum_of_array([1, 2, 3]) #=> 参数匹配,运行正常 Numbers.new.sum_of_array([1.0, 2, 3]) #=> 仅在匹配返回类型时才抛出错误
问题
为何会出现这种行为?为何当参数类型为数组时,Sorbet不执行运行时类型检查?
解答
核心原因:Sorbet的泛型运行时检查策略
- 基础类型与泛型类型的检查差异:
sorbet-runtime对单个基础类型(如Integer)会做即时的严格参数类型检查,但对于T::Array[Integer]这类泛型集合,默认仅检查参数是否为Array实例,不会递归校验集合内的元素类型。这是出于性能考量——递归检查大量集合元素会显著增加运行时开销。 - 报错的真实触发点:
sum_of_array([1.0, 2, 3])的报错并非来自参数类型检查,而是因为数组包含Float元素,调用sum后返回Float类型,与方法签名声明的返回值Integer不匹配,触发了返回值的类型校验错误。
如何启用集合元素的运行时检查
如果需要强制校验数组内的元素类型,可以使用T.cast显式校验:
# 显式校验数组元素类型,触发参数错误 validated_array = T.cast([1.0, 2, 3], T::Array[Integer]) Numbers.new.sum_of_array(validated_array)
内容的提问来源于stack exchange,提问作者Rostislav Zhuravsky
相关产品推荐
相关产品推荐

