我使用的是Ruby 3.2,我有一个自定义类Foo
(出于演示目的),它存储一个值数组。
我有另一段代码不受我的控制,它使用Enumerable#grep
和Enumerable#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命令似乎没有调用它。
有什么办法吗?
1条答案
按热度按时间bjp0bcyl1#
仔细看看
Enumerable#grep
的文档[* 粗体斜体 * 强调我的]:grep(pattern)
→array
grep(pattern) {|element| ... }
→array
返回
self
中匹配给定模式的基于对象的元素的数组。如果没有给定块,则返回一个数组,其中包含 *
pattern === element
* 为true的每个元素[...]===
triple-equals case subsumption binary infix operator的左侧,这意味着消息===
被发送到 pattern,而不是 element。===
三重等于 * 大小写包容 * 二进制中缀运算符是not commutative。如果你想让你的对象可以被
Regexp
匹配,那么你需要把它表示成可以被Regexp
匹配的东西,也就是String
:但是,请 * 仅 * 在你的对象实际上是IS-A字符串 * 的情况下 * 这样做,也就是说,如果它可以被认为是字符串的子类型/特殊化。
“三个字母”转换方法(
to_str
,to_int
,to_ary
,to_float
,to_hash
等,是的,我知道它们不是所有的三个字母)应该 * 只 * 为 * 真正 * 是subtypes的对象实现。也就是说,to_str
只能由String
的 * 子类型 *(对象IS-A字符串)实现,但由于技术原因不能是String
的 * 子类 *。如果你看看Ruby核心库中哪些对象实现了
to_str
,你会发现只有三个,String
和另外两个,我认为另外两个是 * 错误的 , 不应该 * 实现它。to_int
或to_float
也是如此。这些应该被“明智地”使用。它们被用于 * 隐式转换 *,伴随着所有的危险。如果您实现
Foo#to_str
,您应该非常确定您真的希望Foo
在需要String
的地方被静默地转换为String
everywhere,而不是例如raise
和Exception
。所有这些都是在说:尝试将
Regexp
与不是String
的东西匹配是奇怪的。你确定这是你想要的吗?或者你的设计中有什么不太正确的地方?