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

uzo*_*uzo 51 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" 
Run Code Online (Sandbox Code Playgroud)

我认为这个return关键字在Ruby中是可选的,return无论你是否请求它,你总是在想.鉴于这种情况,我觉得很奇怪,foobar有不同的输出由事实来确定foo包含一个明确的returnProc f.

有谁知道为什么会这样?

sep*_*p2k 83

Ruby有三个结构:

  1. 不是一个对象,并且由创建{... }do... end.
  2. PROCProc通过创建的对象Proc.newproc.
  3. 拉姆达Proc通过创建lambda(或proc在红宝石1.8).

Ruby有三个从某些东西返回的关键字:

  1. return 终止它所在的方法或lambda.
  2. next 终止它所在的块,proc或lambda.
  3. break 终止产生于块的方法或调用它所在的proc或lambda.

在lambdas中,无论出于何种原因,都return表现得像next.nextbreak以它们的方式命名,因为它们最常用于方法,例如each,终止块将导致迭代继续使用集合的下一个元素,并且终止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"
Run Code Online (Sandbox Code Playgroud)

  • 顺便说一句,我认为我们在回答一个不同的问题上都做得很好:)关于为什么,我认为只有Matz知道,闭包周围的很多东西都违反了最小惊讶原则。 (2认同)

Sam*_*ron 13

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

该行为在Proc实现中定义.Lambda小号表现不同,所以如果你想你的return小号不退出封闭的方法,使用了lambda表达式.或者,省略return您的关键字Proc.

对Rubys闭合的深入调查就在这里.这是一个很棒的展示.

所以:

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) 
Run Code Online (Sandbox Code Playgroud)


Vit*_*ner 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
Run Code Online (Sandbox Code Playgroud)

相当于

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

  return "return from foo" 
end
Run Code Online (Sandbox Code Playgroud)

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

相反:

def foo
  f = proc { return "return from foo from inside proc" }
  f.call # control stasy in foo here
  return "return from foo" 
end
Run Code Online (Sandbox Code Playgroud)

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

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

def foo
  unonymous_proc()
  return "return from foo" 
end
Run Code Online (Sandbox Code Playgroud)

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

  • 尽管这是一个老问题,但请注意Ruby 1.8.7和1.9.3之间存在差异,后者Kernel.proc的行为类似于Proc.new而不是lambda. (5认同)