为什么显式返回在 Proc 中会产生影响?

发布于 2024-08-04 18:50:09 字数 629 浏览 11 评论 0原文

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 具有不同的输出,这是由 foo 包含显式 return 的事实决定的Proc f 中的 code>。

有谁知道为什么会这样?

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" 

I thought the return keyword was optional in Ruby and that you are always returning whether you request it or not. Given that, I find it surprising that foo and bar have different output determined by the fact that foo contains an explicit return in Proc f.

Does anyone know why this is the case?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

等待我真够勒 2024-08-11 18:50:09

Ruby 具有三种结构:

  1. 不是对象,而是由 { ... }do 创建的...结束
  2. proc 是由 Proc.newproc 创建的 Proc 对象。
  3. lambda 是由 lambda(或 Ruby 1.8 中的 proc)创建的 Proc

Ruby 具有三个从某些内容返回的关键字:

  1. return 终止它所在的方法或 lambda。
  2. next 终止它所在的块、proc 或 lambda。
  3. break 终止生成块或调用其所在的 proc 或 lambda 的方法。

在 lambda 中,无论出于何种原因,return 的行为类似于 nextnextbreak 之所以如此命名,是因为它们最常与 each 等方法一起使用,其中终止块将导致迭代继续使用集合的下一个元素,终止每个将导致您中断跳出循环。


If you use return inside the definition of foo, you will return from foo, even if it is inside a block or a proc. To return from a block, you can use the next keyword instead.

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"

Ruby has three constructs:

  1. A block is not an object and is created by { ... } or do ... end.
  2. A proc is a Proc object created by Proc.new or proc.
  3. A lambda is a Proc created by lambda (or proc in Ruby 1.8).

Ruby has three keywords that return from something:

  1. return terminates the method or lambda it is in.
  2. next terminates the block, proc, or lambda it is in.
  3. break terminates the method that yielded to the block or invoked the proc or lambda it is in.

In lambdas, return behaves like next, for whatever reason. next and break are named the way they are because they are most commonly used with methods like each, where terminating the block will cause the iteration to resume with the next element of the collection, and terminating each will cause you to break out of the loop.


If you use return inside the definition of foo, you will return from foo, even if it is inside a block or a proc. To return from a block, you can use the next keyword instead.

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"
離殇 2024-08-11 18:50:09

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

该行为在 Proc 实现中定义。 Lambda 的行为有所不同,因此如果您希望返回不退出封闭方法,请使用 lambda强>。或者,从您的 Proc 中省略 return 关键字。

对 Ruby 闭包的深入研究在这里。这是一次精彩的曝光。

所以:

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) 

This is the semantics for Procs; it is not necessarily the semantics for all blocks. I agree this is a bit confusing. It is there for added flexibility (and perhaps partially cause Ruby has no spec except for its implementation).

The behavior is defined in the Proc implementation. Lambdas behave differently, so if you would like your returns not to exit out of the enclosing method, use lambdas. Or, omit the return keyword from your Proc.

A deep investigation of Rubys closures is here. It is a fantastic exposé.

So:

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) 
¢蛋碎的人ぎ生 2024-08-11 18:50:09

这样想: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 返回并继续执行下一条语句。

Think of it this way: Proc.new just create a block of code that is part of the calling function. proc/lambda create an anonymous function that has special bindings. A little code examples will help:

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

is equivalent to

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

  return "return from foo" 
end

so it is clear that the return will just return from the function 'foo'

in contrast:

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

is equivalent to (ignoring the bindings since not used in this example):

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

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

Which is as clearly will not return from foo and continue to the next statement instead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文