Ruby链如何工作?

JZ.*_*JZ. 5 ruby chaining

为什么你可以链接这个:

"Test".upcase.reverse.next.swapcase
Run Code Online (Sandbox Code Playgroud)

但不是这个:

x = My_Class.new 
x.a.b.c
Run Code Online (Sandbox Code Playgroud)

哪里

class My_Class 

  def a 
    @b = 1 
  end 

  def b
    @b = @b + 2 
  end 

  def c 
    @b = @b -72 
  end

end
Run Code Online (Sandbox Code Playgroud)

Rya*_*igg 7

upcase,reverse,nextswapcase方法的所有返回String的对象,所有这些方法是......你猜对了,String对象!

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

"Test".upcase.reverse.next.swapcase
Run Code Online (Sandbox Code Playgroud)

您甚至可以随意拨打电话reverse:

"Test".reverse.reverse.reverse.reverse.reverse.reverse.reverse.reverse
Run Code Online (Sandbox Code Playgroud)

所有因为它返回相同类型的对象,一个String对象!

但你不能用你的MyClass:

x = My_Class.new

x.a.b.c
Run Code Online (Sandbox Code Playgroud)

为此,该a方法必须返回一个具有在b其上定义的方法的对象.现在,这似乎只有那样的实例MyClass.要使其工作,您可以创建a对象本身的返回值,如下所示:

def a
  @b += 2
  self
end
Run Code Online (Sandbox Code Playgroud)

对此进行外推,该b方法还需要返回,self因为该c方法仅适用于MyClass类的实例.c在这个例子中返回什么并不重要,因为它是链的末尾.它可以返回self,它不能.薛定谔的法.在我们打开盒子之前,没有人知道.


Phr*_*ogz 6

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

"Test".upcase.reverse.next.swapcase
Run Code Online (Sandbox Code Playgroud)

...几乎完全一样......

a = "Test"
b = a.upcase
c = b.reverse
d = c.next
e = d.swapcase
Run Code Online (Sandbox Code Playgroud)

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

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'
Run Code Online (Sandbox Code Playgroud)

使用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>'
Run Code Online (Sandbox Code Playgroud)


cam*_*cam 5

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

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

def a 
  @b = 1 
  self
end 
Run Code Online (Sandbox Code Playgroud)