代码之家  ›  专栏  ›  技术社区  ›  Justin L.

了解Ruby Enumerable映射(使用更复杂的块)

  •  5
  • Justin L.  · 技术社区  · 16 年前

    假设我有一个函数

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

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

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

    我用我的函数,用一个do-end块在map中运行它:

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

    3 回复  |  直到 11 年前
        1
  •  13
  •   x1a4    16 年前

    你离得太近了。只需删除 return S和你是金色的。

    这是因为块传递给 map 是一个过程(即用 Proc.new ,而不是lambda。一 返回 在一个过程中,不仅仅是跳出过程,而是跳出执行的方法(即调用 call 上)另一方面,lambda中的返回只跳出lambda。

    这个 proc 方法返回Ruby1.8中的lambda和Ruby1.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'
    

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

        2
  •  9
  •   Andrew Grimm Alex Wayne    16 年前

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

    simple.map do |n|
      if n%2 == 0
        next :even
      else
        next :odd
      end
    end
    
        3
  •  3
  •   Bubonic Pestilence    14 年前

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

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