yield:为什么我不能写:测试方法{i.uppercase}

时间:2009-09-14 15:53:05

标签: ruby yield

def test_method
  ["a", "b", "c"].map {|i| yield(i) }
end

如果我这样调用test_method:

p test_method {|i| i.upcase }
# => ["A", "B", "C"]

为什么我需要块内的{| i |},而不只是这样说:

p test_method { i.upcase }

我之所以这么认为是因为在test_method中调用yield时,我们已经有{| i |}

  ["a", "b", "c"].map {|i| yield(i) }

5 个答案:

答案 0 :(得分:3)

如果你来自Groovy背景,他们有一个隐式迭代器,甚至来自Scala,你可以在没有这个的情况下使用| i |使用部分函数,​​然后你可能会发现它是一个逻辑问题,但是,目前在Ruby 1.9或者甚至在Rails中你可以做的最好的事情是使用像JRL所提到的Symbol#to_block方法:

p test_method &:upcase

只需在方法名称前添加&:

答案 1 :(得分:2)

块需要参数化值才能传递给upcase方法。它可以这样看:如果你省略了| i |在块中,它无法“捕获”所产生的值(i在test_method中)

答案 2 :(得分:2)

在Ruby 1.9中,你可以写:

 p test_method &:upcase

答案 3 :(得分:2)

正如ennuikiller所说,您必须定义您希望命名从yield语句传回的变量的名称。这与变量的范围有关。传递给test_method的块内部的范围不知道i变量。你可以随意调用它。

例如,您可以执行以下操作:

def test_method
  ["a", "b", "c"].map { |i| yield(i) }
end

p test_method { |some_variable_name| some_variable_name.upcase }

仅仅因为测试方法知道它,并不意味着传递给测试方法的块将知道它。

修改1:要提供更多信息,如果它更清晰一点,您可以按照以下方式重新定义test_method

def test_method(&block)
  if not block.nil?
    ["a", "b", "c"].map { |i| yield(i) }
  end
end

答案 4 :(得分:0)

当你打电话

p test_method {|i| i.upcase}

方法定义中使用的|i|不可见(其范围仅在{}内。 特别是您正在构建一个采用单个变量的块,要构建该块,您必须指定该变量。注意

p test_method {|j| j.upcase}

也有效。