一元与号运算符并将过程作为 Ruby 中的参数传递 [英] Unary Ampersand Operator and passing procs as arguments in Ruby

查看:41
本文介绍了一元与号运算符并将过程作为 Ruby 中的参数传递的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法理解下面的代码.

I'm having trouble understanding this code below.

我了解到一元与号运算符并将过程作为参数传递给方法的想法.但我真的无法将self 传递给language.call.我是这样理解的:我们将 self 作为参数传递给 proc/block 语言.这对我来说没有任何意义.有人可以解释一下吗?:)

I get the idea of Unary Ampersand Operator and passing procs as arguments to methods. But I really can't wrap my head around passing self to the language.call. I understand it like this: we're passing self as an argument to the proc/block language. It doesn't make any sense to me. Can someone please explain? :)

class Translator    
  def speak &language
    language.call(self)    
  end

  protected

  def french
    'bon jour'  
  end

  def spanish
    'hola'   
  end

  def turkey
    'gobble'   
  end

  def method_missing(*args)
    'awkward silence'
  end 
end

我们将其用于:

translator.speak(&:spanish)

推荐答案

这个例子很好地将多个 Ruby 概念联系在一起.正因为如此,我将尝试解释所有这些.

This example beautifully ties together multiple Ruby concepts. Because of that, I will try to explain all of them.

Ruby 中的方法可以优雅地接受块(代码段):

Methods in Ruby can accept blocks (pieces of code) in elegant matter:

def run_code
  yield
end

run_code { puts 42 } # => prints 42

  1. Proc 类似于块,但它们是实际的可寻址对象:

deep_thought = proc { puts 42 }
deep_thought.call # => prints 42

  1. 在使用 & 运算符调用方法时,您可以将 proc 转换为块:
  1. You can turn a proc into a block when calling a method with the & operator:

def run_code
  yield
end

deep_thought = proc { puts 42 }
run_code(&deep_thought) # => prints 42

  1. 过程和块可以接受参数:

def reveal_answer
  yield 5_000
end

deep_thought = proc do |years_elapsed|
  years_elapsed >= 7_500_000 ? 42 : 'Still processing'
end

reveal_answer(&deep_thought) # => 'Still processing'

  1. 您可以在方法签名中使用 & 将块转换为 proc:
  1. You can turn a block into proc using & in the method signature:

def inspector(&block)
  puts block.is_a?(Proc)
  puts block.call
end

inspector { puts 42 } # => prints true and 42
inspector(&proc { puts 42 }) # => the same

  1. Symbol#to_proc 创建一个调用对象上同名方法的过程:
  1. Symbol#to_proc creates a proc that calls methods with the same name on the object:

class Dummy
  def talk
    'wooooot'
  end
end

:talk.to_proc.call(Dummy.new) # => "wooooot"

换句话说,

:bar.to_proc.call(foo)

几乎等同于

foo.bar

  1. BasicObject#method_missing:

当您尝试调用对象上的方法时,Ruby 会遍历它的祖先链,搜索具有该名称的方法.如何构建链是一个不同的主题,足够长的另一天,重要的是如果直到最底部(BasicObject)都没有找到该方法,则对相同的方法执行第二次搜索链 - 这次是一个名为 method_missing 的方法.它作为参数传递原始方法的名称加上它收到的任何参数:

When you try to call a method on an object, Ruby traverses it's ancestor chain, searching for a method with that name. How the chain is constructed is a different topic, lengthy enough for another day, the important thing is that if the method is not found til the very bottom (BasicObject), a second search is performed on the same chain - this time for a method called method_missing. It gets passed as arguments the name of the original method plus any argument it received:

class MindlessParrot
  def method_missing(method_name, *args)
    "You caldt #{method_name} with #{args} on me, argh!"
  end
end

MindlessParrot.new.foo          # => "You caldt foo with [] on me, argh!"
MindlessParrot.new.bar :baz, 42 # => "You caldt bar with [:baz, 42] on me, argh!"

<小时>

那么在我们的具体案例中,这一切意味着什么?让我们假设一秒钟没有 protected.



So what does all this mean in our specific case? Lets assume for a second there was no protected.


translator.speak(&:spanish)

调用方法 Translator#speak 并将 :spanish 转换为块.


Translator#speak 接受该块并将其转换为名为 language 的过程,并调用它,将 self 作为参数传递.


selfTranslator 的一个实例,因此,它有方法 speak, french, spanishturkeymethod_missing.


所以:

calls the method Translator#speak with :spanish converted to block.


Translator#speak takes that block and transforms it to a proc, named language, and calls it, passing self as argument.


self is an instance of Translator, therefore, it has the methods speak, french, spanish, turkey and method_missing.


And so:

Translator.new.speak(&:spanish)

相当于:

:spanish.to_proc.call(Translator.new)

相当于:

Translator.new.spanish

给我们hola".

现在,把protected 拿回来,我们translator 对象的所有语言方法都还存在,但它们不能被外人直接访问.


就像你不能打电话

Now, taking the protected back, all the language methods of our translator object are still present, but they can not be directly accessed by outsiders.


Just as you can't call

Translator.new.spanish

并期待 "hola" 回来,你不能打电话

and expect "hola" back, you can't call

Translator.new.speak(&:spanish)




并且由于该方法不可直接访问,因此将其视为未找到并调用 method_missing,从而使我们尴尬的沉默".

这篇关于一元与号运算符并将过程作为 Ruby 中的参数传递的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆