5

为什么你可以链接这个:

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

3 回答 3

7

、和方法都返回对象upcase,所有这些方法都是为了……你猜对了,对象!reversenextswapcaseStringString

当您调用一个方法时(通常情况下,例如 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,它不能。薛定谔的法。在我们打开盒子之前没有人知道。

于 2011-02-03T01:25:02.190 回答
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>'
于 2011-02-03T01:58:02.487 回答
5

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

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

def a 
  @b = 1 
  self
end 
于 2011-02-03T01:19:29.633 回答