为什么显性回报会对Proc产生影响?

时间:2009-09-16 22:03:20

标签: ruby return proc-object

def foo
  f = Proc.new { return "return from foo from inside proc" }
  f.call # control leaves foo here
  return "return from foo" 
end

def bar
  b = Proc.new { "return from bar from inside proc" }
  b.call # control leaves bar here
  return "return from bar" 
end

puts foo # prints "return from foo from inside proc" 
puts bar # prints "return from bar" 

我认为return关键字在Ruby中是可选的,并且无论您是否请求,您总是return。鉴于此,我发现foobar具有不同的输出,这是由fooreturn中包含明确的Proc f这一事实所确定的。

有谁知道为什么会这样?

3 个答案:

答案 0 :(得分:80)

Ruby有三个结构:

  1. 不是对象,由{ ... }do ... end创建。
  2. proc 是由ProcProc.new创建的proc对象。
  3. lambda 是由Proc(或Ruby 1.8中的lambda)创建的proc
  4. Ruby有三个从某些东西返回的关键字:

    1. return终止它所在的方法或lambda。
    2. next终止它所在的块,proc或lambda。
    3. break终止产生于块的方法或调用它所在的proc或lambda。
    4. 在lambdas中,return表现得像next,无论出于何种原因。 nextbreak以它们的方式命名,因为它们最常用于each等方法,其中终止块将导致迭代继续 next 元素集合,终止each会导致中断退出循环。

      <小时/> 如果您在return的定义中使用foo,则会从foo返回,即使它位于块或proc中。要从块中返回,您可以改为使用next关键字。

      def foo
        f = Proc.new { next "return from foo from inside proc" }
        f.call # control leaves foo here
        return "return from foo" 
      end
      puts foo # prints "return from foo"
      

答案 1 :(得分:12)

这是Proc s的语义;它不一定是所有块的语义。我同意这有点令人困惑。它是为了增加灵活性(也许部分原因导致Ruby没有规范,除了它的实现)。

行为在Proc实施中定义。 Lambda的行为有所不同,因此如果您希望return 不要退出,请使用 lambdas 。或者,省略return中的Proc关键字。

对Rubys封闭的深入调查is here。这是一个很棒的展示。

所以:

def foo   
  f = Proc.new {
    p2 = Proc.new { return "inner proc"};
    p2.call
    return "proc"
  }
  f.call
  return "foo"
end

def foo2
  result = Proc.new{"proc"}.call
  "foo2 (proc result is: #{result})"
end

def bar
  l = lambda { return "lambda" }
  result = l.call
  return "bar (lambda result is: #{result})"
end

puts foo
# inner proc
puts foo2
# foo (proc result is: proc) 
puts bar
# bar (lambda result is: lambda) 

答案 2 :(得分:7)

以这种方式思考:Proc.new只是创建一个代码块,它是调用函数的一部分。 proc / lambda创建一个具有特殊绑定的匿名函数。一些代码示例将有所帮助:

def foo
  f = Proc.new { return "return from foo from inside Proc.new" }
  f.call # control leaves foo here
  return "return from foo" 
end

相当于

def foo
  begin
    return "return from foo from inside begin/end" }
  end

  return "return from foo" 
end

所以很明显,返回只会从函数'foo'

返回

相反:

def foo
  f = proc { return "return from foo from inside proc" }
  f.call # control stasy in foo here
  return "return from foo" 
end

等同于(忽略自此示例中未使用的绑定):

def unonymous_proc
  return "return from foo from inside proc"
end

def foo
  unonymous_proc()
  return "return from foo" 
end

显然不会从foo返回并继续下一个语句。