加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

ruby Enumerable#first vs #take

发布时间:2020-12-17 02:54:59 所属栏目:百科 来源:网络整理
导读:ruby Enumerable / Array first(n)和take(n)之间有什么区别? 我模糊地回忆起take与懒惰评估有关,但我无法弄清楚如何使用它来做到这一点,并且找不到任何有用的谷歌搜索或文档. “take”是google的硬方法名称. first(n)和take(n)是documented非常相同,不太有
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 lazy,它列出了所有懒惰实现的方法.该列表确实包含take,但不包含first.也就是说,在懒惰的序列中,保持懒惰,而不是.

以下是一些示例,它们的工作方式不同:

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.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读