简体   繁体   English

什么`&method(:method_ name)`在ruby中意味着什么?

[英]What does `&method(:method_ name)` mean in ruby?

I was trying to create a class that has a private class method. 我试图创建一个具有私有类方法的类。 I want this private class method available to be used inside an instance method. 我希望这个私有类方法可用于实例方法。

The following was my first attempt: 以下是我的第一次尝试:

class Animal
  class << self
    def public_class_greeter(name)
      private_class_greeter(name)
    end

  private
    def private_class_greeter(name)
      puts "#{name} greets private class method"
    end
  end

  def public_instance_greeter(name)
    self.class.private_class_greeter(name)
  end
end

Animal.public_class_greeter('John') works fine, printing John greets private class method . Animal.public_class_greeter('John')工作正常,打印John greets private class method

However, Animal.new.public_instance_greeter("John") throws an error: NoMethodError: private method 'private_class_greeter' called for Animal:Class . 但是, Animal.new.public_instance_greeter("John")抛出一个错误: NoMethodError: private method 'private_class_greeter' called for Animal:Class

That is expected, as the invocation self.class.private_class_greeter is same as Animal.private_class_greeter , which obviously throws an error. 这是预期的,因为调用self.class.private_class_greeterAnimal.private_class_greeter相同,这显然会引发错误。

After searching on how this can be fixed, I came up with the following code, that does the job: 在搜索了如何解决这个问题之后,我想出了以下代码:

class Animal
  class << self
    def public_class_greeter(name)
      private_class_greeter(name)
    end

  private
    def private_class_greeter(name)
      puts "#{name} greets private class method"
    end
  end

  define_method :public_instance_greeter, &method(:private_class_greeter)
end

I don't exactly understand what is happening here: &method(:private_class_greeter) . 我不完全理解这里发生了什么: &method(:private_class_greeter)

Could you please explain what does this mean? 你能解释一下这是什么意思吗?

If I were to replace: 如果我要替换:

define_method :public_instance_greeter, &method(:private_class_greeter)

with: 有:

def public_instance_greeter
  XYZ
end

then, what should be the content in place of XYZ ? 那么,代替XYZ的内容应该是什么?

How does Ruby parse &method(:private_class_greeter) ? Ruby解析&method(:private_class_greeter)如何?

The expression &method(:private_class_greeter) is 表达式&method(:private_class_greeter)

  • the value of the method call method(:private_class_greeter) 方法调用method(:private_class_greeter)的值method(:private_class_greeter)
  • prefixed with the & operator. &运算符为前缀。

What does the method method do? method方法有什么作用?

The method method looks up the specified method name in the current context and returns a Method object that represents it. method方法在当前上下文中查找指定的方法名称,并返回表示它的Method对象。 Example in irb : irb示例:

def foo
  "bar"
end

my_method = method(:foo)
#=> #<Method: Object#foo>

Once you have this method, you can do various things with it: 拥有此方法后,您可以使用它执行各种操作:

my_method.call
#=> "bar"

my_method.source_location   # gives you the file and line the method was defined on
#=> ["(irb)", 5]

# etc.

What is the & operator for? 什么是&运营商?

The & operator is used to pass a Proc as a block to a method that expects a block to be passed to it. &运算符用于Proc作为块传递给期望将块传递给它的方法。 It also implicitly calls the to_proc method on the value you pass in, in order to convert values that are not Proc into a Proc . 它还隐式调用传入的值的to_proc方法,以便将非Proc值转换为Proc

The Method class implements to_proc — it returns the contents of the method as a Proc . Method类实现to_proc - 它将方法的内容作为Proc Therefore, you can prefix a Method instance with & and pass it as a block to another method: 因此,您可以使用&作为Method实例的前缀,并将其作为块传递给另一个方法:

def call_block
  yield
end

call_block &my_method   # same as `call_block &my_method.to_proc`
#=> "bar"

The define_method method just happens to take a block with the contents of the new method that is being defined. define_method方法恰好采用了正在定义的新方法的内容的块。 In your example, &method(:private_class_greeter) passes in the existing private_class_greeter method as a block. 在您的示例中, &method(:private_class_greeter)将现有的private_class_greeter方法作为块传递。


Is this how &:symbol works? 这是&:symbol工作原理吗?

Yes. 是。 Symbol implements to_proc so that you can simplify your code like this: Symbol实现to_proc以便您可以像这样简化代码:

["foo", "bar"].map(&:upcase)
#=> ["FOO", "BAR"]

# this is equivalent to:
["foo", "bar"].map { |item| item.upcase }

# because
:upcase.to_proc

# returns this proc:
Proc { |val| val.send(:upcase) }

How can I replicate &method(:private_class_greeter) ? 我怎样才能复制&method(:private_class_greeter)

You can pass in a block that calls the target method: 您可以传入一个调用目标方法的块:

define_method :public_instance_greeter do |name|
  self.class.send(:private_class_greeter, name)
end

Of course, then you don't need to use define_method anymore, which results in the same solution Eric mentioned in his answer : 当然,那么你不再需要使用define_method ,这导致了Eric在他的回答中提到的相同解决方案:

def public_instance_greeter(name)
  self.class.send(:private_class_greeter, name)
end

First, take good care with your indentation. 首先,要小心你的缩进。 private should be 2 spaces to the right: it gives the impression that public_instance_greeter is private otherwise. private应该是右边的2个空格:它给人的印象是public_instance_greeter是私有的。

If you don't care about encapsulation, you could simply use Kernel#send : 如果你不关心封装,你可以简单地使用Kernel#send

class Animal
  class << self
    def public_class_greeter(name)
      private_class_greeter(name)
    end

    private
    def private_class_greeter(name)
      puts "#{name} greets private class method"
    end
  end

  def public_instance_greeter(name)
    self.class.send(:private_class_greeter, name)
  end
end

Animal.public_class_greeter('John')
# John greets private class method
Animal.new.public_instance_greeter("John")
# John greets private class method

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM