Ruby链如何工作?

时间:2011-02-03 01:15:48

标签: ruby chaining

为什么你可以链接这个:

"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

3 个答案:

答案 0 :(得分:7)

upcasereversenextswapcase方法都返回String个对象,所有这些方法都是为了......你猜对了,{ {1}}对象!

当你调用一个方法时(通常比如99.9999%的时间),它会返回一个对象。该对象具有在其上定义的方法,然后可以调用它来解释为什么可以这样做:

String

您甚至可以根据需要多次拨打"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,但它不能。薛定谔的 cat 方法。在我们打开盒子之前,没有人知道。

答案 1 :(得分:6)

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

"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>'

答案 2 :(得分:5)

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

例如,您的a方法当前正在返回1b不是数字的方法。你会想要修改它:

def a 
  @b = 1 
  self
end