You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Sorbet抽象单例方法实现版本化Typed Struct反序列化

问题原因

这个报错是Sorbet对mixes_in_class_methods的类型处理规则导致的:通过该方法混合的类方法,只会挂载到包含模块的类的单例类上,既不属于VersionedStruct模块本身的实例方法,也不属于T.class_of(VersionedStruct)的方法,所以你直接cast到这两个类型都找不到对应的version和migrate方法。

解决方案

直接把类型指定为你定义的VersionedStruct::ClassMethods即可,这个模块里已经声明了所有抽象类方法的签名,所有包含VersionedStruct的类的单例类都会自动被Sorbet识别为该模块的子类型。

需要修改的代码只有两处:

  1. 修改migrate私有方法的参数类型,把struct的类型从VersionedStruct换成VersionedStruct::ClassMethods
  2. load方法里的T.cast目标类型也同步换成VersionedStruct::ClassMethods

修改后的DataDeserializer代码如下:

class DataDeserializer

  sig { params(data_class: String, data_version: Integer, data: T::Hash[Symbol, T.untyped]).returns(T.any(MyStruct, MyOtherStruct, T::Struct)) }
  def load(data_class, data_version, data)
    struct_class = Object.const_get(data_class)

    migrated_data = if struct_class.include?(VersionedStruct)
      migrate(data_version, T.cast(struct_class, VersionedStruct::ClassMethods), data)
    else
      data
    end

    struct_class.new(migrated_data)
  end

  private

  sig { params(data_version: Integer, struct: VersionedStruct::ClassMethods, data: T::Hash[Symbol, T.untyped]).returns(T::Hash[Symbol, T.untyped]) }
  def migrate(data_version, struct, data)
    return data if data_version == struct.version

    struct.migrate(data)
  end
end

另外补充一个业务代码的小问题:你现在写的MyStruct.migrate方法在v2_field存在时会返回nil,会导致后续new方法报错,建议改成return data if data[:v2_field]。

内容的提问来源于stack exchange,提问作者leifg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 19:36:02