这是什么'&'红宝石意味着什么?

时间:2016-05-06 14:35:57

标签: ruby

https://github.com/activeadmin/activeadmin/blob/1c85c5654a2ce1d43d4c64d98b928ff133d46406/lib/active_admin.rb#L95

此代码中的&(前缀为ActiveAdmin)是什么意思?

def before_load(&block)
  ActiveSupport::Notifications.subscribe(
    ActiveAdmin::Application::BeforeLoadEvent,     
    &ActiveAdmin::Event.wrap_block_for_active_support_notifications(block)
  )
end

3 个答案:

答案 0 :(得分:4)

在函数&'splats'块中(也在其上调用to_proc),类似于常规参数的*

这有点等同于

def before_load(&block) # this binds provided block into block variable
  ActiveSupport::Notifications.subscribe(ActiveAdmin::Application::BeforeLoadEvent){|some_params_maybe|
    ActiveAdmin::Event.wrap_block_for_active_support_notifications(block).call(some_params_maybe)
  }
end

答案 1 :(得分:2)

通常&调用to_proc对象的方法,例如gets.split.map(&:to_i)用于读取整数行,这与map { |e| e.to_i }

相同

在方法参数中,它出现在最后一个参数中,表示您传递给的代码块,请查看以下代码以获取详细信息。

def g
    puts yield "g"
end

def h(block)
    puts block.call "h"
end

def f(&block)
    puts block.class        # => Proc
    puts block.call "f"     # => hello f
    g &block                # => hello g       passed as code block
    h block                 # => hello h       passed as proc
end

f { |x| "hello " + x }

答案 2 :(得分:1)

Following article对'&'的使用提供了很好的解释在Ruby中:

隐式阻止 Ruby中的方法可以通过各种有趣的方式获取参数。一个特别有趣的案例是Ruby方法占用了一个块。

事实上,所有Ruby方法都可以隐式地占用一个块,而不需要在参数列表中指定它或者必须在方法体中使用块,例如:

def hello
end

hello do
  puts "hello"
end

这将毫无困难地执行,但由于我们没有执行我们传入的块,因此不打印任何内容。当然,我们可以轻松地通过yielding执行块:< / p>

def hello
  yield if block_given?
end

hello do
  puts "hello"
end

这次我们得到一些输出:

hello

我们yielded到方法内的块,但是方法占用块的事实仍然是隐含的。

由于Ruby允许将任何对象传递给方法并让该方法尝试将此对象用作其块,因此它变得更加有趣。如果我们在方法的最后一个参数前放置一个&符号,Ruby将尝试将此参数视为方法的块。如果参数已经是Proc对象,Ruby将简单地将它与方法相关联作为其块。

  def hello
      yield if block_given?
    end

    blah = -> {puts "lambda"}

hello(&blah)
lambda

如果参数不是Proc,那么 Ruby会尝试将其转换为一个(通过调用to_proc),然后将其与方法关联作为其块

def hello
  yield if block_given?
end

class FooBar
  def to_proc
    -> {puts 'converted lambda'}
  end
end

hello(&FooBar.new)
converted lambda

所有这一切看起来都非常清楚,但是如果我想采用与方法相关联的块并将其传递给另一个方法呢?我们需要一种方法来引用我们的块。

明确的阻止 当我们编写方法定义时,我们可以明确声明我们希望这个方法可能需要一个块。令人困惑的是,Ruby也使用了&符号:

def hello(&block)
  yield if block_given?
end

hello do
  puts "hello"
end

以这种方式定义我们的方法,给我们一个名称,通过该名称我们可以在方法体中引用我们的块。由于我们的块是Proc对象,而不是yielding,我们可以call

def hello(&block)
  block.call if block_given?
end

hello do
  puts "hello"
end

我更喜欢block.call而不是yield,这会让事情更清晰。当然,当我们定义我们的方法时,我们不必使用名称'block',我们可以这样做:

def hello(&foo)
  foo.call if block_given?
end

hello do
  puts "hello"
end

说完了; 'block'是一个很好的约定。