ruby Enumerable#first vs #take
ruby Enumerable / Array first(n)和take(n)之间有什么区别?
我模糊地回忆起take与懒惰评估有关,但我无法弄清楚如何使用它来做到这一点,并且找不到任何有用的谷歌搜索或文档. “take”是google的硬方法名称. first(n)和take(n)是documented非常相同,不太有帮助. first → obj or nil first(n) → an_array Returns the first element,or the first n elements,of the enumerable. If the enumerable is empty,the first form returns nil,and the second form returns an empty array. – take(n) → array Returns first n elements from enum. 告诉我“与懒惰评估有关”是不够的,我有点记得已经,我需要一个如何使用它的例子,与之相比. 解决方法
好吧,我看过源代码(Ruby 2.1.5).在引擎盖下,如果首先提供一个参数,它会转发它.否则,它返回一个值:
static VALUE enum_first(int argc,VALUE *argv,VALUE obj) { NODE *memo; rb_check_arity(argc,1); if (argc > 0) { return enum_take(obj,argv[0]); } else { memo = NEW_MEMO(Qnil,0); rb_block_call(obj,id_each,first_i,(VALUE)memo); return memo->u1.value; } } 另一方面,take需要一个参数,并始终返回给定大小或更小的数组,其中包含从头开始的元素. static VALUE enum_take(VALUE obj,VALUE n) { NODE *memo; VALUE result; long len = NUM2LONG(n); if (len < 0) { rb_raise(rb_eArgError,"attempt to take negative size"); } if (len == 0) return rb_ary_new2(0); result = rb_ary_new2(len); memo = NEW_MEMO(result,len); rb_block_call(obj,take_i,(VALUE)memo); return result; } 所以,是的,这就是为什么这两个如此相似的原因.唯一的区别似乎是,第一个可以不带参数调用,并且不会输出数组,而是输出单个值.另一方面,< ...>.第一(1)等同于< ...> .take(1).就如此容易. 然而,对于懒惰的集合,情况有所不同.懒惰集合中的第一个仍然是enum_first,如上所示,它是enum_take的快捷方式.然而,采用C编码的lazy_take: static VALUE lazy_take(VALUE obj,VALUE n) { long len = NUM2LONG(n); VALUE lazy; if (len < 0) { rb_raise(rb_eArgError,"attempt to take negative size"); } if (len == 0) { VALUE len = INT2FIX(0); lazy = lazy_to_enum_i(obj,sym_cycle,1,&len,0); } else { lazy = rb_block_call(rb_cLazy,id_new,&obj,lazy_take_func,n); } return lazy_set_method(lazy,rb_ary_new3(1,n),lazy_take_size); } …不会立即评估,需要.force调用. 事实上,它暗示了in the docs under 以下是一些示例,它们的工作方式不同: lz = (1..Float::INFINITY).lazy.map{|i| i } # An infinite sequence,evaluating it head-on won't do # Ruby 2.2 also offers `.map(&:itself)` lz.take(5) #=> #<Enumerator::Lazy: ...> # Well,`take` is lazy then # Still,we need values lz.take(5).force #=> [1,2,3,4,5] # Why yes,values,finally lz.first(5) #=> [1,5] # So `first` is not lazy,it evaluates values immediately 通过在2.2之前的版本中运行并使用2.2的代码(< ...> .lazy.map(&:本身))可以获得一些额外的乐趣,因为这样当你失去懒惰的那一刻将立即引发NoMethodError. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |