1

我有这个描述类型的 preudo 代码

    type MyType1 = {
        type: :type1,
        field1: number,
        field2: any
    } | {
        type: :type2,
        field3: string
    } | {
        type: :type4,
        field4: SomeOtherType
    } | {
        type: :type5,
        field5: string,
        field6: integer,
        field7: float
    } | {
        type: :type6
    }

我在 Ruby 中是这样表达的:

    class MyType1
        attr_reader :type, :field1, :field2, :field3, :field4, :field5, :field6, :field7

        def init_with_type_1(field1:, field2:)
          @type = :type1
          @field1 = field1
          @field2 = field2
        end

        def init_with_type_2(field3:)
          @type = :type2
          @field3 = field3
        end

        # and so on...

    end

有没有更好、更惯用、更简单的方法?

我不考虑使用第三方 gems 和库。

4

1 回答 1

0

我会这样做:

Type1 = Struct.new(:field1, :field2)
Type2 = Struct.new(:field3)

class MyType1
  def initialize(some_type_item)
    @data = some_type_item
  end
  def self.init_with_type_1(f1, f2)
    self.new(Type1.new(f1,f2))
  end
  def type
    @data.class # Or @data.class.name, if you prefer
  end
  def field1
    # Raises exception, if we don't have Type1 
    @data.field1
  end
end

Forwardable我对此进行了显式编码,但是使用Ruby 标准库中的模块可以使一些工作(例如 field1 的定义等)变得更简单(更少输入) 。此外,init_with_type可以使用循环生成这些方法,如果您想要在此处存储许多不同的类型,这可以简化事情。

尽管我问自己,为什么MyType1要为此引入一个类,但我将其建模为接近您的初始解决方案;在定义了 Type1、Type2 等之后,我会简单地做一个

myTypeVar = Type2.new(4711)
puts "myTypeVar is a #{myTypeVar.class}"
puts myTypeVar.field3 # OK
puts myTypeVar.field1 # Exception!
于 2021-03-17T10:36:32.050 回答