在 Ruby 中使用 to_enum 创建可枚举对象有什么好处?
为什么要使用 to_enum 方法而不是直接使用对象来创建对 Ruby 中对象的代理引用?我想不出任何实际用途,试图理解这个概念和概念。有人可能会使用它,但我见过的所有例子似乎都很微不足道。
例如,为什么使用:
"hello".enum_for(:each_char).map {|c| c.succ }
而不是
"hello".each_char.map {|c| c.succ }
我知道这是一个非常简单的例子,有人有任何现实世界的例子吗?
Why would you create a proxy reference to an object in Ruby, by using the to_enum method rather than just using the object directly? I cannot think of any practical use for this, trying to understand this concept & where someone might use it, but all the examples I have seen seem very trivial.
For example, why use:
"hello".enum_for(:each_char).map {|c| c.succ }
instead of
"hello".each_char.map {|c| c.succ }
I know this is a very simple example, does anyone have any real-world examples?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如果没有提供块,大多数接受块的内置方法都会返回一个枚举器(例如示例中的 String#each_char )。对于这些,没有理由使用
to_enum
;两者将产生相同的效果。不过,有一些方法不返回枚举器。在这种情况下,您可能需要使用
to_enum
。另一个例子,
Array#product
、#uniq
和#uniq!
不用于接受块。在 1.9.2 中,这一点已更改,但为了保持兼容性,没有块的表单无法返回Enumerator
。人们仍然可以“手动”使用to_enum
来获取枚举器:to_enum
的主要用途是当您实现自己的迭代方法时。您通常会将以下内容作为第一行:Most built-in methods that accept a block will return an enumerator in case no block is provided (like
String#each_char
in your example). For these, there is no reason to useto_enum
; both will have the same effect.A few methods do not return an Enumerator, though. In those case you might need to use
to_enum
.As another example,
Array#product
,#uniq
and#uniq!
didn't use to accept a block. In 1.9.2, this was changed, but to maintain compatibility, the forms without a block can't return anEnumerator
. One can still "manually" useto_enum
to get an enumerator:The main use of
to_enum
is when you are implementing your own iterative method. You typically will have as a first line:我认为这与内部和外部迭代器有关。当您返回这样的枚举器时:
p 是外部枚举器。外部迭代器的优点之一是:
所以,使用外部迭代器你可以这样做,例如:
I think it has something to do with internal and external Iterators. When you return an enumerator like this:
p is an external enumerator. One advantage of external iterators is that:
So, with external iterator you can do, e.g.:
假设我们想要获取一个键数组和一个值数组并将它们缝合在哈希中:
With #to_enum
Without #to_enum:
阅读起来要容易得多第一种方法,你觉得呢?不是很容易,但想象一下如果我们以某种方式操作 3 个数组中的项目会怎样? 5? 10?
Let's say we want to take an array of keys and an array of values and sew them up in a Hash:
With #to_enum
Without #to_enum:
It's much easier to read the first method, don't you think? Not a ton easier, but imagine if we were somehow manipulating items from 3 arrays? 5? 10?
这并不完全是您问题的答案,但希望它是相关的。
在第二个示例中,您调用
each_char
而不传递块。当不使用块调用时,each_char
返回一个Enumerator
,因此您的示例实际上只是执行同一操作的两种方法。 (即两者都会导致创建可枚举对象。)This isn't quite an answer to your question, but hopefully it is relevant.
In your second example you are calling
each_char
without passing a block. When called without a blockeach_char
returns anEnumerator
so your examples are actually just two ways of doing the same thing. (i.e. both result in the creation of an enumerable object.)它非常适合大型或无限的生成器对象。
例如,下面将为您提供整个斐波那契数列的枚举器,从 0 到无穷大。
to_enum
有效地允许您使用常规的yields
编写此代码,而不必弄乱Fiber
。然后,您可以根据需要对其进行切片,这将非常节省内存,因为内存中不会存储任何数组:
It's great for large or infinite generator objects.
E.g., the following will give you an enumerator for the whole Fibonacci seequence, from 0 to infinity.
to_enum
effectively allows you to write this with regularyields
without having to mess withFiber
s.You can then slice it as you want, and it will be very memory efficient, since no arrays will be stored in memory: