【问题标题】:Understanding Ruby Enumerable#map (with more complex blocks)理解 Ruby Enumerable#map(带有更复杂的块)
【发布时间】:2011-03-03 18:57:44
【问题描述】:

假设我有一个函数

def odd_or_even n
  if n%2 == 0
    return :even
  else
    return :odd
  end
end

我有一个简单的可枚举数组

simple = [1,2,3,4,5]

然后我通过 map 运行它,使用我的函数,使用 do-end 块:

simple.map do
  |n| odd_or_even(n)
end
# => [:odd,:even,:odd,:even,:odd]

如果不首先定义函数,我怎么能做到这一点?例如,

# does not work
simple.map do |n|
  if n%2 == 0
    return :even
  else
    return :odd
  end
end

# Desired result:
# => [:odd,:even,:odd,:even,:odd]

不是有效的 ruby​​,编译器会因为我考虑它而生我的气。但是我将如何实现一个等效的东西呢?

编辑

实际上,我的问题的解决方案对我来说远没有它背后的动机/推理那么重要,以帮助我更多地了解 ruby​​ 块的工作原理:)

【问题讨论】:

  • 为了它的价值,你可以做 1.even?还是 1.odd?在红宝石中 >= 1.8.7

标签: ruby language-features enumerable


【解决方案1】:

你离得很近。只需删除 returns 即可。

这是因为传递给 map 的块是一个 proc(即使用 Proc.new 创建的),而不是 lambda。 proc 中的return 不仅会跳出 proc - 它会跳出执行(即调用call)proc 的方法。另一方面,lambda 中的 return 只跳出 lambda。

proc 方法在 Ruby 1.8 中返回一个 lambda,在 Ruby 1.9 中返回一个 Proc。最好不要使用此方法,并明确说明您要使用的构造。

我猜你在尝试这个时要么在 IRB 中,要么在一个普通的 ruby​​ 脚本中。

a = Proc.new { return }
a.call # fails. Nothing to return from.

def foobar
  a = Proc.new { return }
  a.call
  puts 'hello' # not reached. The return within the proc causes execution to jump out of the foobar method.
end
foobar # succeeds, but does not print 'hello'. The return within the proc jumps out of the foobar method.

b = lambda { return }
b.call # succeeds. The return only returns from the lambda itself.

def bazquux
  b = lambda { return }
  b.call
  puts 'hello' # this is reached. The lambda only returned from itself.
end
bazquux # succeeds, and prints 'hello'

从中吸取的教训是使用隐式返回,除非你不能,我猜。

【讨论】:

  • 有什么原因为什么会发生这种情况吗?该块是否像隐式返回一样简单地输出最后执行的命令?我问这个是因为我希望能够预测会发生什么;让这些出来似乎有点……随机。
  • 简短版本是“它是 procs 和 lambdas 之间的区别之一。”致力于更好的解释。是的,块只会返回其中最近评估的表达式。
  • 感谢您的解释;它非常彻底和有帮助=)只是最后一个问题......是否可以将 lambda 作为一个块传递?到#map,也许?
  • 在某些情况下您可能需要使用next
  • 是的,您可以将 lambda 作为块传递,但在这种情况下它就像一个 proc(即在其中返回将失败。)add_one = lambda { |n| n + 1 }; [1, 2, 3].map &add_one # [2, 3, 4]
【解决方案2】:

我怀疑这可能是一个重复的问题,但要给出一个块外的值,请使用next

simple.map do |n|
  if n%2 == 0
    next :even
  else
    next :odd
  end
end

【讨论】:

  • 嗯,这似乎正是我想要的 :) 谢谢 :)
【解决方案3】:

使用安德鲁答案的最短变体:

simple.map { |n| next :even if n % 2 == 0; :odd }

【讨论】:

  • 更进一步:simple.map {|n| next n%2 == 0 ? :even : :odd } ;-)
猜你喜欢
  • 2017-05-25
  • 2015-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-21
  • 2015-05-16
  • 2012-12-11
  • 2013-11-19
相关资源
最近更新 更多