for循环与each的区别

for和each的区别主要在于:

  1. for是通过调用each实现,因此for更慢一些
  2. for会在each的scope之外创建一个局部变量,这在某些情况下会引发问题

关于第二点,下面的代码可以很好的说明这个问题:


irb> [1, 2, 3].each do |m| puts m end
irb> puts m
NameError: undefined local variable or method `m' for main:Object
irb> for n in [1, 2, 3] do puts n; end
irb> puts n
=> 3

如果你不了解这一点,那么在某些特殊的情况下,你可能会遇到麻烦,Ruby Forum的某个用户提交的一段代码很好的说明了for可能引发的问题:


a = []
for n in [1, 2, 3] do
a << Proc.new {puts "#{n}"}
end
[1,2,3].each do |m|
a << Proc.new {puts "#{m}"}
end
a.each { |p| p.call }

运行结果:

3
3
3
1
2
3

很显然,for循环的结果不是我们所期待的,因此,结论就是:应该尽可能的使用each替代for循环。

更新:感谢ShiningRay,应该使用each代替for的真正原因是,for实际上是通过each实现的,但它在each的scope外面定义了一个同名变量,下面的代码可以说明问题:

>> a = “1\n2\n”
>> def a.each
>> yield(1)
>> end
>> for i in a
>> puts i
>> end
1
=> nil

也就是说“for i in [1, 2]”就相当于“i = nil;[1,2].each do |i|”,因此前面的结论是不正确的,for应该比each慢(没有进行过测试),这才是for真正的问题所在。

This entry was posted in Ruby. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.
  • http://shiningray.cn ShiningRay

    for in do
    end
    do可以省略
    另外貌似for其实从根本上应该是调用each方法的
    或者说,有个迭代器的概念在里面(我从Python的角度看)
    因为出错的时候,for的块会显示为each?

    irb(main):019:0> for i in [1,2,3]
    irb(main):020:1> puts i / 0
    irb(main):021:1> end
    ZeroDivisionError: divided by 0
    from (irb):20:in `/’
    from (irb):20
    from (irb):19:in `each’
    from (irb):19
    from :0

  • admin

    each是Array类的一个方法,定义如下:

    VALUE
    rb_ary_each(ary)
    VALUE ary;
    {
    long i;

    for (i=0; ilen; i++) {
    rb_yield(RARRAY(ary)->ptr[i]);
    }
    return ary;
    }

    for是Ruby关键字,由YACC生成的语法解析器直接执行,至于Backtrace,只是由于for的intern_name也是“each”,但for并没有调用each,它由语法分析器定义。

  • http://iceskysl.1sters.com/ IceskYsl

    我一般使用 while 代替 for

  • http://shiningray.cn ShiningRay

    我认为应该还是是迭代器的问题,再例如Hash,each返回键值对

    irb(main):011:0> for i in {‘a’=> 1, ‘b’ => 2, ‘c’ => 3}
    irb(main):012:1> p i
    irb(main):013:1> end
    ["a", 1]
    ["b", 2]
    ["c", 3]
    => {“a”=>1, “b”=>2, “c”=>3}
    irb(main):014:0> {‘a’ => 1, ‘b’ => 2, ‘c’ => 3}.each do |i|
    irb(main):015:1* p i
    irb(main):016:1> end
    ["a", 1]
    ["b", 2]
    ["c", 3]
    => {“a”=>1, “b”=>2, “c”=>3}

    String,则会自动以回车分割

    irb(main):028:0> for i in “a\nb\nc”
    irb(main):029:1> p i
    irb(main):030:1> end
    “a\n”
    “b\n”
    “c”
    => “a\nb\nc”
    irb(main):031:0> “a\nb\nc”.each do |i|
    irb(main):032:1* p i
    irb(main):033:1> end
    “a\n”
    “b\n”
    “c”
    => “a\nb\nc”

    所以我认为for 绝对是内部调用迭代器each,这点应该和python类似,而不是for的intern_name是each

  • http://letrails.cn Yuanyi Zhang

    你说的对,for的确是通过each实现的:

    >> a = “1\n2\n”
    >> def a.each
    >> yield(1)
    >> end
    >> for i in a
    >> puts i
    >> end
    1
    => nil

    只不过for在调用each之前先定义了一个局部变量:

    for i in [1, 2]

    等于:

    i = nil
    [1,2].each do |i| end

    也就是说for的问题在于它在each的scope外面定义了一个同名变量。

    帖子已更新

  • http://blog.rubyee.org/2010/07/30/rails-guy%e5%b0%8f%e6%8a%84%e5%a4%a7%e5%85%a8/ rails guy小抄大全 – RubyEE.org – about Ruby,Rails,Sinatra,Mac OS & iPhone app

    [...] for循环与each的区别(–>認真看回復) http://www.letrails.cn/archives/difference-between-for-loop-and-each/ [...]

无觅相关文章插件,快速提升流量