为什么Enumerable#find /#detect即使在Hash上调用也会返回一个数组?

Enumerable#find / #detect的文档说:

find(ifnone = nil) { |obj| block } → obj or nil
find(ifnone = nil) → an_enumerator

枚举中的每个条目传递给返回第一个块不为false的块。 如果没有对象匹配,则调用ifnone并在指定时返回其结果,否则返回nil

但是,当在Hash上调用它时,结果将类型更改为Array而不是原始Hash。

是关于此数据类型的一些实现错误还是一些历史约定?

 {a: 'a', b:'b'}.find {|k, v| v == 'b'} # => [:b, 'b'] 

Hash#detectinheritance自Enumerable#detect方法。

Enumerable模块基于包含Enumerable的类的each方法生成多个方法(例如sortminmax包括detect等)。

它并不关心each方法的实施方式

“……产生了该集合的连续成员。”来自ruby-doc

所以对于Hash#detect方法,它依赖于Hash#each的行为,即:

对hsh中的每个键调用一次,将键值对作为参数传递。 如果没有给出块,则返回枚举器。

 h = { "a" => 100, "b" => 200 } h.each {|key, value| puts "#{key} is #{value}" } 

因为Hash#each将哈希产生为两对数组,所以从Enumerable模块inheritance的所有方法都基于此工作。

这就是为什么Hash#detect产生一个两元素数组而不是一个哈希对象本身。

find是根据eacheach在Hash上调用时,都返回数组forms的键值对,每个元素包含2个元素。 这就是为什么find返回一个数组。

使用带有哈希的检测/查找

使用哈希,检测/查找将哈希中的每个键/值对传递给块,您可以将其“捕获”为:

一个双元素数组,键为元素0,其对应值为元素1

 h = {:a => 'a', :b => 'b'} p h.find {|k| pk ; k[1] == 'b'} 

输出:

 [:a, "a"] [:b, "b"] [:b, "b"] 

两个单独的项目,其中键作为第一项,其对应值作为第二项。

 h = {:a => 'a', :b => 'b'} p h.find {|k, v| puts k,v ; v == 'b'} 

输出:

 a a b b [:b, "b"] 

要了解有关此主题的更多信息,请Enumerating Ruby's “Enumerable” Module, Part 3: “detect”, aka “find”Enumerating Ruby's “Enumerable” Module, Part 3: “detect”, aka “find”