Как работает Ruby Chaining? - PullRequest
       14

Как работает Ruby Chaining?

5 голосов
/ 03 февраля 2011

Почему вы можете это:

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

7 голосов
/ 03 февраля 2011

Все методы upcase, reverse, next и swapcase возвращают 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, он не мог. Метод Шредингера кошка . Никто не знает, пока мы не откроем коробку.

6 голосов
/ 03 февраля 2011

В качестве поддержки других ответов, этот код:

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

Используя метод tap в Ruby 1.9, мы можем даже сделать это более явным:

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>'
5 голосов
/ 03 февраля 2011

Последнее выражение в функции - это неявное возвращаемое значение. Вам нужно вернуть self, если вы хотите связать методы таким образом.

Например, ваш метод a в настоящее время возвращает 1. b не метод для чисел. Вы захотите изменить это так:

def a 
  @b = 1 
  self
end 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...