如何将类型限制为接口的类而不是该接口的实例?

给定模块中的以下接口:

module Action
  abstract def perform
end

我想用它来实例化实现它的不同类:

class Run
  include Action

  def perform
    puts "run!"
  end
end

class Jump
  include Action

  def perform
    puts "jump!"
  end
end

我知道可以定义像 [] of Action 这样的数组并且能够存储 Action 的实例,但我对类而不是实例感兴趣 .

我想知道如何定义类型限制,以便我可以存储对实现接口而不是特定实例的 class 的引用 .

我的目标是能够实例化某个类的新实例,并能够在其中调用 perform 方法 .

此时可以编写以下代码:

actions = [Run, Jump]
actions.each do |klass|
  instance = klass.new.as(Action)
  instance.perform
end

事情会有效,但是由于类型限制有点严格,因此无法将该类列表存储到实例变量中 .

该案例的类型限制语法是什么?

回答(2)

2 years ago

想到的第一个想法是使用 [] of Action.class ,但这不起作用 . 也许这应该有效,但它需要在编译器中进行更改/增强 .

在此期间,您可以这样做:

module Action
  abstract def perform
end

class Run
  include Action

  def perform
    puts "run!"
  end
end

class Jump
  include Action

  def perform
    puts "jump!"
  end
end

module ActionFactory
  abstract def new : Action
end

struct GenericActionFactory(T)
  include ActionFactory

  def new
    T.new
  end
end

ary = [] of ActionFactory
ary << GenericActionFactory(Run).new
ary << GenericActionFactory(Jump).new

action = ary[0].new
p action

action = ary[1].new
p action

2 years ago

@asterite对工厂建议的另一种方法是在类上使用模块和 extend ,但也使用它来定义实例变量的类型:

module Action
  module Interface
  end

  macro included
    extend Interface
  end

  abstract def perform
end

class Run
  include Action

  def perform
    puts "run!"
  end
end

class Jump
  include Action

  def perform
    puts "jump!"
  end
end

list = [] of Action::Interface
list << Run
list << Jump

list.each do |klass|
  instance = klass.new
  instance.perform
end

这允许我也使用 Action.class 作为类型要求,因此只能使用实现 Action 的类,并且使用 Action::Interface 删除了对从数组中获取的元素执行任何转换的需要:

class Worker
  @actions = [] of Action::Interface

  def add(action : Action.class)
    @actions << action
  end

  def perform
    @actions.each do |klass|
      instance = klass.new
      instance.perform
    end
  end
end

a = Worker.new
a.add Run
a.add Jump
a.add Jump
a.perform