在Ruby中,如何编写一个简单的方法,可以与&:symbol一起使用?

In Ruby, how do you write a simple method that can be used with &:symbol?

这篇 article 触及了问题,但没有给出解决方案。

这开始于我想编写一个方法并有选择地向它传递一个可以为 null 或 ???? 的参数(proclambdamethodblock, ???).我们暂时称它为 block,因为 block 有效。 block 接受一个必需的参数。该方法及其调用的示例如下:

#!/usr/bin/env ruby

def foo(&proc)
  puts "before"
  if proc
    yield "passed to proc"
  end
  puts "after"
end

def add_message(s)
  puts "from add_message #{s}"
end

foo { |s| add_message(s) }
foo

输出为:

before
from add_message passed to proc
after
before
after

太棒了。但是,我想做的是能够像这样调用 foofoo(&:add_message)。但我不能。更改上面的第 15 行我得到:

before
./temp.rb:11:in `add_message': wrong number of arguments (given 0, expected 1) (ArgumentError)
    from ./temp.rb:6:in `foo'
    from ./temp.rb:15:in `<main>'

而且,正如上面的文章提到的,现在的元数是 -2。那么,我该如何编写一个像 add_message 这样可以与 &:add_message 一起使用的简单方法呢?要么!!! 99.99% 的情况都是如此,请让我了解如何执行此操作的正确轨道。

class Integer
    def set
        return self + 1
    end
end

p [1,2,3,4,5,6].map(&:set)

我认为当你可以使用 &: 语法时,已经为 class 定义了一个方法,就像上面的

问题是 Symbol#to_proc 没有创建正确调用 add_message 方法的过程。

# `yield` will pass it's arguments to proc
>> :add_message.to_proc.call('passed to proc')
# => ArgumentError

这会调用 'passed to proc'.add_message,因为我们的方法是在 Object 中定义的,它在 String 上调用时有效,但是它缺少必需的参数。

解决方案是制作一个可以接受与 add_message 方法相同的参数并将它们传递给该方法的过程。我们可以使用 Object#method 那个 returns Method 对象,它实现了它自己的 to_proc 并且与方法具有相同的 arity。

>> method(:add_message).to_proc.arity
=> 1

>> method(:add_message).to_proc.call('passed to proc')
from add_message passed to proc
>> foo(&method(:add_message))
before
from add_message passed to proc
after

来自the Ruby docs

Conversion of other objects to procs

Any object that implements the to_proc method can be converted into a proc by the & operator, and therefore can be consumed by iterators.

class Greeter
  def initialize(greeting)
    @greeting = greeting
  end

  def to_proc
    proc {|name| "#{@greeting}, #{name}!" }
  end
end

hi = Greeter.new("Hi")
hey = Greeter.new("Hey")
["Bob", "Jane"].map(&hi)    #=> ["Hi, Bob!", "Hi, Jane!"]
["Bob", "Jane"].map(&hey)   #=> ["Hey, Bob!", "Hey, Jane!"]

Of the Ruby core classes, this method is implemented by Symbol, Method, and Hash.

因此,当您传递一个前面带有一元符号的参数时,to_proc 会被调用。 &: “语法”实际上是 & 在符号文字上调用,即 &(:foobar),并且 Symbol.to_proc 具有将符号转换为方法调用的行为参数,即这两个大致等价(模命名参数转发)

:foobar.to_proc
proc { |x, *args| x.foobar(*args) }

Ruby 的 Method 类型也实现了 to_proc,所以如果你有一个名为 foobar 的独立方法(在模块上,比如说,Example), 然后你可以调用 Example.method(:foobar) 并得到一个 & 兼容的对象。如果你有一个“top-level”方法,那么它可能是 并且在没有显式接收者的情况下调用 method 将起作用。

该引用中提到的另一种类型是散列,它可以变成一个函数,将它们的键映射到它们的值(如果不存在匹配的键,则返回 nil)。当然,您始终可以自己实现一个名为 to_proc 的方法 类,它的工作方式与任何 built-in 类型一样好。