Ruby [双飞燕] 闭包和绑定疑问

LinuxGit · 2012年04月28日 · 最后由 fsword 回复于 2012年04月28日 · 3273 次阅读
def multiplier(n)
  lambda { |data| data.map { |x| x*n } }
end

doubler = multiplier(2)
puts doubler.([1,2,3])
eval("n=3", doubler)
#doubler.binding.eval("n=3")
#eval("n=3", doubler.binding)
puts doubler.([1,2,3])


书中说可以用 eval("n=3", doubler) 代替注释的行,我测试报错,求解,谢谢。: test.rb:7:in eval': wrong argument type Proc (expected Binding) (TypeError) from test.rb:7:in' [双飞燕] P202

eval("n=3", doubler.binding) 是不是少打了 .binding 或是打错字?

首先,我估计 [双飞燕] 可能有中文版和英文版,我的是英文版的 PDF,这部分内容在英文版的 217 页,第 6.6.2 章节中,所以楼主最好以后留下章节信息,因为章节信息在任何版本中应该都是对应的。

其次在英文版中,这里的内容和注释内容是这样写的: eval("n=3", doubler.binding) # Or doubler.binding.eval("n=3") in Ruby 1.9 也就是说,如果楼主用的 ruby 版本是 1.9 以上,那么就需要用注释中的第二种写法

~ $ irb
>> def multiplier(n)
>>   lambda {|data| data.collect{|x| x*n } } end
=> nil
>> doubler = multiplier(2)
=> #<Proc:0x007fd3420d1b38@(irb):2 (lambda)>
>> puts doubler.call([1,2,3])
2
4
6
=> nil
>> doubler.binding.eval("n=3")
=> 3
>> puts doubler.call([1,2,3])
3
6
9
=> nil

#2 楼 @lgn21st #doubler.binding.eval("n=3") #eval("n=3", doubler.binding) 这两句我测试都是正常的,我用的中文版,ruby 1.9.3p125 我的书中说 eval 有个快捷方式,直接传递 Proc 对象给他,不需要传递 Proc 的 binding 对象,就是写成 eval("n=3", doubler) 我用这种方式写就报上面的错了。

我不是太确定中文版为什么要这样说,但是我建议你对照一下英文版,看看英文版是不是也这么说,如果尽信书不如无书(英文原版不在此例!)

#4 楼 @lgn21st 嗯,谢谢,我找下英文版对照一下。

#5 楼 @LinuxGit 我已经看过了,英文原版也有这一段,从测试来看,在 Ruby 1.9.3-p125 中已经不能这么用了。

As a shortcut, the eval method allows you to pass a Proc object directly instead of passing the Binding object of the Proc. So we could replace the eval invocation above with:

    eval("n=3", doubler)

Bindings are not only a feature of closures. The Kernel.binding method returns a Binding object that represents the bindings in effect at whatever point you happen to call it.

#1 楼 @Juanito 这句测试是正常的,把注释的那行换成 eval("n=3", doubler) 就报错了。我对照下英文版。

#6 楼 @lgn21st 嗯,谢谢,这么大晚上了还在回复我。晚安。

#8 楼 @LinuxGit 刚刚测试了一下,以及检查了 API,如 #6 楼 @lgn21st 说的,1.9.2+ 不行用了,1.8.7 可以。

Ruby core API Proc 1.8.7 Proc 1.9.2 Proc 1.9.3

明显发现 1.9.2 及 1.9.3 少了无 binding 的例子。

提示很明显啊

/root/ruby/test.rb:284:in `eval': wrong argument type Proc (expected Binding) (TypeError)

我猜测主要是 1.9 针对 binding 对象已经提供了 eval 方法,根本没必要再通过之前的给 eval 提供第二参数的方式来运行了吧。再说了,原来那种所谓隐式转换,实在不是什么好的编程习惯,我发现 Ruby1.9 中大把这种似是而非 (容易引起混淆), 甚至之前当作好东西来卖弄的东西,都取缔了。

#9 楼 @Juanito 嗯,谢谢,我竟没有查官方文档。

问题已经回答的很完整了,我来佩服一下大伙动作快吧

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