我想创建一个Set,它只允许添加某种(kind_of?
)个对象,并在尝试添加外来对象时引发异常。
我还没有找到任何资源,在我开始搞乱ruby核心课程之前,我会感激任何建议如何以“不显眼”的方式实现这一目标。
另外:我的目标实际上是创建一个“模板化”容器类,就像在C ++中一样(例如Set),这样我就可以在实例定义时设置一次类型,并在类级别上比较两个集合,如果它们是相同(即接受相同的类型)但保持与“默认”集的互操作性,作为示例set_instance_a.class == set_instance_b.class
如果它们接受相同类型的对象,则应该为true。
我的想法是重载::[]
运算符,以便我可以编写类似my_set = MySet[Foo]
的内容,它应返回仅接受MySet
类型对象的Foo
实例
谢谢!
答案 0 :(得分:3)
require "set"
class MySet < Set
def add e
raise "Invalid element #{e}" unless e.kind_of?(Foo)
super(e)
end
end
或者,如果您不想使用子类,则:
require "set"
class Set
alias original_add :add
def add e
raise "Invalid element #{e}" unless e.kind_of?(Foo)
original_add(e)
end
end
编辑于2017年添加 要做到这一点,不要以现代方式进行子类化,
require "set"
module MySet
def add e
raise "Invalid element #{e}" unless e.kind_of?(Foo)
super(e)
end
end
class Set
prepend MySet
end
答案 1 :(得分:3)
Class
也是一个对象,因此您可以根据需要在运行时创建新类。 Class
构造函数允许您指定基类,甚至可以在新类的上下文中评估代码:
new(super_class = Object)→a_class
new(super_class = Object){| mod | ......}→a_class使用给定的超类创建一个新的匿名(未命名)类(如果没有给出参数,则为
Object
)。您可以通过将类对象赋值给常量来为类赋予名称。如果给出了一个块,它将传递给该类对象,并使用
class_eval
在该类的上下文中计算该块。
class_eval
允许您定义方法和别名。这一切意味着你可以这样说:
module Kernel
def MySet(c)
Class.new(Set) do
@@allowed = c
def add(o)
raise ArgumentError.new("#{o.class} is stinky!") if(!o.is_a?(@@allowed))
super(o)
end
alias_method :<<, :add
end
end
end
然后:
s = MySet(String).new
s.add(6) # Exception!
s << 'pancakes' # Allowed
我将MySet
方法修补为Kernel
,以便与Array
,Complex
,......方法 - 假装成为函数一致,你可以把它放在任何你想要的地方。