一元Ampersand运算符并在Ruby中传递proc作为参数

时间:2016-05-05 17:37:46

标签: ruby

我无法理解下面的代码。 我得到了Unary Ampersand运算符的概念,并将procs作为方法的参数传递。但我真的无法绕过自己的语言来解决问题。我理解为这样:我们将self作为参数传递给proc / block语言。这对我没有任何意义。有人可以解释一下吗? :) 班级翻译   def speak& language     language.call(个体经营)   结束   保护   def法语     ' bon jour'   结束   def西班牙语     ' HOLA'   结束   def火鸡     '吞噬'   结束   def method_missing(* args)     尴尬的沉默'   结束 结束 我们正在使用它: translator.speak(安培;:西班牙语)

1 个答案:

答案 0 :(得分:7)

这个例子巧妙地将多个Ruby概念联系在一起。因此,我将尝试解释所有这些。

  1. Ruby中的方法可以在优雅的事物中接受块(代码片段):

    def run_code
      yield
    end
    
    run_code { puts 42 } # => prints 42
    
    1. Proc类似于块,但它们是实际的可寻址对象:
    2. deep_thought = proc { puts 42 }
      deep_thought.call # => prints 42
      
      1. 使用&运算符调用方法时,可以将proc转换为块:
      2. def run_code
          yield
        end
        
        deep_thought = proc { puts 42 }
        run_code(&deep_thought) # => prints 42
        
        1. Procs和block可以接受参数:
        2. 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:
          2. 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创建一个proc,它调用对象上具有相同名称的方法:
            2. 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
              2. 当您尝试在对象上调用方法时,Ruby会遍历它的祖先链,搜索具有该名称的方法。如何构建链是一个不同的主题,对于另一天来说足够长,重要的是如果找不到方法直到最底部(BasicObject),则在同一链上执行第二次搜索 - 这一个名为method_missing的方法的时间。它作为参数传递原始方法的名称加上它收到的任何参数:

                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


                translator.speak(&:spanish)
                

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


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


                selfTranslator的一个实例,因此,它包含方法speakfrenchspanishturkeymethod_missing


                所以:

                Translator.new.speak(&:spanish)
                

                相当于:

                :spanish.to_proc.call(Translator.new)
                

                相当于:

                Translator.new.spanish
                

                给我们"hola"

                现在,取回protected,我们的translator对象的所有语言方法仍然存在,但外人无法直接访问它们。


                就像你不能打电话一样

                Translator.new.spanish
                

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

                Translator.new.speak(&:spanish)
                




                由于该方法无法直接访问,因此系统会将其视为未找到并调用method_missing,从而为我们提供"awkward silence"