新手问题 Ruby scan 方法的一个疑问

rubyu2 · 2015年07月31日 · 最后由 rubyu2 回复于 2015年08月01日 · 3953 次阅读

最近刚读完《松本行弘的程序世界》,有这样一段描述。

8.1.10 字符串扫描

"afdasfasdfads".scan(/fa./){|s| p s }

下面代码执行同样的动作。它不生成无用的数组,效率稍高一点。

"afdasfasdfads".scan(/fa./).each{|s| p s }

有这样的疑问,为什么第二种代码不生成无用的数组

于是看了 API:

Both forms iterate through str, matching the pattern (which may be a Regexp or a String). For each match, a result is generated and either added to the result array or passed to the block.

这里也是描述了either added to the result array or passed to the block

irb(main):007:0> "afdasfasdfads".scan(/fa./).each{|s| p s }
"fas"
"fad"
=> ["fas", "fad"]
irb(main):008:0> "afdasfasdfads".scan(/fa./).each{|s| p s }.class
"fas"
"fad"
=> Array

在我这里可以正常输出数组,使用的 ruby 版本为 2.0.0p451

#1 楼 @tiseheaini

返回结果肯定是数组了。

a result is generated and either added to the result array or passed to the block

结果可以是生成一个数组或者传给一个 Block。

看源码就知道啦:

static VALUE
rb_str_scan(VALUE str, VALUE pat)
{
   ...
    if (!rb_block_given_p()) {
        ....
        return ary;
    }

    ...
    return str;
}

不过你是不是看反了,"afdasfasdfads".scan(/fa./).each{|s| p s }才会生成数组。

#4 楼 @yesmeck 测试 100W 次,发现后者稍慢不到 0.03s;btw,题主没看错

当时没留意这个问题。。惭愧

不过用 set_trace_func 和 disasm 去看调用的过程,并没有发现哪里节省了,scan 是生成了数组并推回栈里再调用的 each,调用次数是后者更多啊

我觉得可能是作者写错了吧。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号