【问题标题】:How does Ruby chaining work?Ruby 链接是如何工作的?
【发布时间】:2011-02-03 01:15:47
【问题描述】:

为什么你可以把这个链接起来:

"Test".upcase.reverse.next.swapcase

但不是这个:

x = My_Class.new 
x.a.b.c

在哪里

class My_Class 

  def a 
    @b = 1 
  end 

  def b
    @b = @b + 2 
  end 

  def c 
    @b = @b -72 
  end

end

【问题讨论】:

标签: ruby chaining


【解决方案1】:

upcasereversenextswapcase 方法都返回 String 对象,所有这些方法都用于......你猜对了,String 对象!

当您调用一个方法时(通常情况下,例如 99.9999% 的时间),它会返回一个对象。这个对象有定义的方法,然后可以调用,这就解释了为什么你可以这样做:

"Test".upcase.reverse.next.swapcase

您甚至可以多次拨打reverse

"Test".reverse.reverse.reverse.reverse.reverse.reverse.reverse.reverse

都是因为它返回同一种对象,String 对象!

但是你不能用你的MyClass 做到这一点:

x = My_Class.new

x.a.b.c

为此,a 方法必须返回一个定义了b 方法的对象。现在,这似乎只有MyClass 的实例才有。要使其正常工作,您可以将 a 的返回值设为对象本身,如下所示:

def a
  @b += 2
  self
end

据此推断,b 方法还需要返回 self,因为 c 方法仅适用于 MyClass 类的实例。在这个例子中c 返回什么并不重要,因为它是链的末端。它可以返回self,但不能。薛定谔的 cat 方法。在我们打开盒子之前没人知道。

【讨论】:

    【解决方案2】:

    作为对其他答案的支持,此代码:

    "Test".upcase.reverse.next.swapcase
    

    ...与...几乎完全相同

    a = "Test"
    b = a.upcase
    c = b.reverse
    d = c.next
    e = d.swapcase
    

    ....除了我上面的代码有额外的变量指向中间结果,而原始代码没有留下额外的引用。如果我们使用您的代码执行此操作:

    x = MyClass.new   # x is an instance of MyClass
    y = x.a           # y is 1, the last expression in the a method
    z = y.b           # Error: Fixnums have no method named 'b'
    

    使用 Ruby 1.9 的 tap 方法,我们甚至可以更明确:

    irb> "Test".upcase.tap{|o| p o}.reverse.tap{|o| p o}.next.tap{|o| p o}.swapcase
    #=> "TEST"
    #=> "TSET"
    #=> "TSEU"
    => "tseu"
    
    irb> class MyClass
    irb>   def a
    irb>     @b = 1
    irb>   end
    irb>   def b
    irb>     @b += 2
    irb>   end
    irb> end
    => nil
    
    irb(main):011:0> x = MyClass.new
    => #<MyClass:0x000001010202e0>
    
    irb> x.a.tap{|o| p o}.b.tap{|o| p o}.c
    #=> 1
    NoMethodError: undefined method `b' for 1:Fixnum
    from (irb):12
    from /usr/local/bin/irb:12:in `<main>'
    

    【讨论】:

      【解决方案3】:

      函数中的最后一个表达式是它的隐式返回值。如果你想链接这样的方法,你需要返回self

      例如,您的a 方法当前返回1b 不是数字的方法。您需要像这样修改它:

      def a 
        @b = 1 
        self
      end 
      

      【讨论】:

        猜你喜欢
        • 2013-10-28
        • 2019-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-07
        • 2014-12-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多