理解Ruby可枚举映射(具有更复杂的块)

理解Ruby可枚举映射(具有更复杂的块),ruby,language-features,enumerable,Ruby,Language Features,Enumerable,假设我有一个函数 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] 如果不首先定义函数,我怎么能做到这一点呢

假设我有一个函数

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块是如何工作的:)

你太接近了。只需删除
返回
s,您就是金色的

这是因为传递到
map
的块是一个过程(即,使用
proc.new
创建),而不是lambda。进程内的
返回
不仅仅跳出进程-它跳出执行(即调用
调用
的)进程的方法。另一方面,lambda中的返回仅从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'

从中可以学到的教训是使用隐式返回,除非你不能,我猜。

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

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

使用Andrew的答案的最短变体:

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

但是,有什么原因会发生这种情况吗?块是否只是发出最后执行的命令,如隐式返回?我这样问是因为我希望能够预测会发生什么;让这些出来似乎有点…随机。简短的版本是“这是PROC和lambdas之间的区别之一。”正在研究更好的解释。是的,块将只返回其中最近计算的表达式;这是非常彻底和有用的=)最后一个问题…是否可以将lambda作为块传递?也许要#map?在某些情况下,您可能需要使用
next
。是的,您可以将lambda作为块传递,但在这种情况下,它的行为就像一个proc(即其中的返回将失败)。
add_one=lambda{n | n+1};[1,2,3].map&add#[2,3,4]
hm,这似乎正是我想要的:)谢谢:)不管它值多少钱,你都可以做1?还是1.5?在ruby中>=1.8.7更进一步:
simple.map{{| n | next n%2==0?:偶数::奇数}
;-)