带有自定义Ruby类的EXP #grep

pobjuy32  于 12个月前  发布在  Ruby
关注(0)|答案(1)|浏览(107)

我使用的是Ruby 3.2,我有一个自定义类Foo(出于演示目的),它存储一个值数组。
我有另一段代码不受我的控制,它使用Enumerable#grepEnumerable#grep_v来搜索数组中的字符串模式。
我想让Foo类与Array#grep一起工作。我看了https://docs.ruby-lang.org/en/3.2/Enumerable.html#method-i-grep,它说,
如果没有给出块,则返回一个数组,其中包含每个pattern = element为true的元素:
我尝试实现一个像这样的#===方法

class Foo
  def initialize(values)
    @values = values
  end

  def ===(pattern)
    @values.any? { |v| v.match?(pattern) }
  end
end

但这似乎不起作用:

[Foo.new(["foo", "bar"]), Foo.new(["zoo"])].grep(/oo/)
=> []

我还可以看到,当我在def ===(pattern)中放置调试器或放置语句时,grep命令似乎没有调用它。
有什么办法吗?

bjp0bcyl

bjp0bcyl1#

仔细看看Enumerable#grep的文档[* 粗体斜体 * 强调我的]:

grep(pattern)array

grep(pattern) {|element| ... }array

返回self中匹配给定模式的基于对象的元素的数组。
如果没有给定块,则返回一个数组,其中包含 * pattern === element * 为true的每个元素[...]

如果你想让你的对象可以被Regexp匹配,那么你需要把它表示成可以被Regexp匹配的东西,也就是String

class Foo
  def initialize(values)
    @values = values
  end

  def to_str = @values.join
end

[Foo.new(%w[foo bar]), Foo.new(['zoo'])].grep(/oo/)
#=> [#<Foo:0xdeadbeef @values=["foo", "bar"]>, #<Foo:0xdeadbeef @values=["zoo"]>]

但是,请 * 仅 * 在你的对象实际上是IS-A字符串 * 的情况下 * 这样做,也就是说,如果它可以被认为是字符串的子类型/特殊化。
“三个字母”转换方法(to_strto_intto_aryto_floatto_hash等,是的,我知道它们不是所有的三个字母)应该 * 只 * 为 * 真正 * 是subtypes的对象实现。也就是说,to_str只能由String的 * 子类型 *(对象IS-A字符串)实现,但由于技术原因不能是String的 * 子类 *。
如果你看看Ruby核心库中哪些对象实现了to_str,你会发现只有三个,String和另外两个,我认为另外两个是 * 错误的 不应该 * 实现它。to_intto_float也是如此。这些应该被“明智地”使用。
它们被用于 * 隐式转换 *,伴随着所有的危险。如果您实现Foo#to_str,您应该非常确定您真的希望Foo在需要String的地方被静默地转换为Stringeverywhere,而不是例如raiseException
所有这些都是在说:尝试将Regexp与不是String的东西匹配是奇怪的。你确定这是你想要的吗?或者你的设计中有什么不太正确的地方?

相关问题