在Ruby 1.8中,proc/lambda和proc .new之间有细微的区别。

这些区别是什么? 你能告诉我如何决定选择哪一个吗? 在Ruby 1.9中,proc和lambda是不同的。怎么回事?


当前回答

值得强调的是,proc中的return返回的是词法上封闭的方法,即创建proc的方法,而不是调用proc的方法。这是procc的闭包属性的结果。所以下面的代码什么都没有输出:

def foo
  proc = Proc.new{return}
  foobar(proc)
  puts 'foo'
end

def foobar(proc)
  proc.call
  puts 'foobar'
end

foo

虽然proc在foobar中执行,但它是在foo中创建的,因此返回退出foo,而不仅仅是foobar。正如Charles Caldwell上面所写的,它有一种GOTO的感觉。在我看来,return在一个在其词法上下文中执行的块中很好,但在一个在不同上下文中执行的proc中使用时就不那么直观了。

其他回答

我没有注意到问题中的第三个方法“proc”有任何注释,它已弃用,但在1.8和1.9中处理方式不同。

下面是一个相当详细的例子,可以很容易地看出三个类似调用之间的差异:

def meth1
  puts "method start"

  pr = lambda { return }
  pr.call

  puts "method end"  
end

def meth2
  puts "method start"

  pr = Proc.new { return }
  pr.call

  puts "method end"  
end

def meth3
  puts "method start"

  pr = proc { return }
  pr.call

  puts "method end"  
end

puts "Using lambda"
meth1
puts "--------"
puts "using Proc.new"
meth2
puts "--------"
puts "using proc"
meth3

一个很好的方法是,lambdas是在它们自己的作用域内执行的(就好像它是一个方法调用一样),而Procs可以被看作是与调用方法内联执行的,至少这是决定在每种情况下使用哪一个的好方法。

值得强调的是,proc中的return返回的是词法上封闭的方法,即创建proc的方法,而不是调用proc的方法。这是procc的闭包属性的结果。所以下面的代码什么都没有输出:

def foo
  proc = Proc.new{return}
  foobar(proc)
  puts 'foo'
end

def foobar(proc)
  proc.call
  puts 'foobar'
end

foo

虽然proc在foobar中执行,但它是在foo中创建的,因此返回退出foo,而不仅仅是foobar。正如Charles Caldwell上面所写的,它有一种GOTO的感觉。在我看来,return在一个在其词法上下文中执行的块中很好,但在一个在不同上下文中执行的proc中使用时就不那么直观了。

简单的回答:重要的是返回的作用:lambda返回自身,proc返回自身和调用它的函数。

不太清楚的是为什么要使用它们。Lambda是我们在函数式编程中所期望的。它基本上是一个匿名方法,当前范围自动绑定。这两个中,应该用的是。

另一方面,Proc对于实现语言本身非常有用。例如,你可以用它们实现“if”语句或“For”循环。在proc中找到的任何返回都将从调用它的方法中返回,而不仅仅是if语句。这就是语言的工作方式,if语句的工作方式,所以我猜Ruby在幕后使用了它,他们只是因为它看起来很强大而公开它。

只有当你创建新的语言结构,如循环,if-else结构等,你才真正需要这个。

我不能说太多细微的差别。但是,我可以指出Ruby 1.9现在允许lambdas和block的可选参数。

下面是1.9版本中stabby lambdas的新语法:

stabby = ->(msg='inside the stabby lambda') { puts msg }

Ruby 1.8没有这种语法。声明blocks/lambdas的传统方式也不支持可选参数:

# under 1.8
l = lambda { |msg = 'inside the stabby lambda'|  puts msg }
SyntaxError: compile error
(irb):1: syntax error, unexpected '=', expecting tCOLON2 or '[' or '.'
l = lambda { |msg = 'inside the stabby lambda'|  puts msg }

然而,Ruby 1.9支持可选参数,即使使用旧语法:

l = lambda { |msg = 'inside the regular lambda'|  puts msg }
#=> #<Proc:0x0e5dbc@(irb):1 (lambda)>
l.call
#=> inside the regular lambda
l.call('jeez')
#=> jeez

如果你想为Leopard或Linux构建Ruby1.9,看看这篇文章(无耻的自我推销)。