/ / Предефинирането на класа в Ruby изглежда включва грешен модул - ruby, class, module, include

Предефинирането на класа в Ruby изглежда включва грешен модул - ruby, class, module, include

Аз идвам от Python фон, и се опитвах да разбера как Ruby включва сравнение с множественото наследяване на Python. super работа.

Аз включих Mod, тогава Mod2, тогава Mod отново. Въпреки това, A все още изглежда, че се прави позоваване Mod2.

module Mod
def foo(x)
x**2
end
end
module Mod2
def foo(x)
x*2
end
end

class A
include Mod
def foo(x)
super(x) + 1
end
end
A.new.foo(5) == 26 # true

class A
include Mod2
def foo(x)
super(x) + 1
end
end
A.new.foo(5) == 11 # true

class A
include Mod
def foo(x)
super(x) + 1
end
end
A.new.foo(5) == 26 # false. Is 11

Защо не е третата A.new.foo(5) връщане 26?

Отговори:

1 за отговор № 1

Мисля, че това, което може да ви липсва, е второто class A ... end не предефинира класа, той го добавя. Позволено е да "отваряте" класа многократно в рубин и да (определяте) каквото искате. Това, и това, което изглежда, вече сте измислили, което е това include повече или по-малко просто изтрива кода от модула в това място в дефиницията на класа, освен ако този модул вече е бил включен, в който случай не прави нищо.

Можете да направите това с всеки клас (независимо дали е препоръчително или не)

class Hash
def to_a
"lol you probably wanted an array here"
end
end
{foo: :bar}.to_a # Returns above string instead of [:foo, :bar]

1 за отговор № 2

Определяне class A(object) в PythonCreates обект с a type на type и __name__ на A, след това възлага този обект на етикета A, Секунда class A(object) Дефиницията създава съвсем ново type предмет, който след това се поставя в етикет А.

Класове в рубин не се съхраняват в етикети и могат да се отварят, за да се добавят повече функционалности. Добър пример за това е 2.days, Rails определя days на цяло число. Без релси, 2.days неуспешна.

По-горе дефинираните 3 класа са приблизително еквивалентни на:

class A
include Mod
def foo(x)
super(x) + 1
end

include Mod2
def foo(x)
super(x) + 1
end

include Mod
def foo(x)
super(x) + 1
end
end

Когато руби вижда второто include Mod, знае Mod вече е включен в класа и го прескача, напускайки foo от Mod2 последната дефиниция.

Ако премахнете foo от по-късни определения, A все още има достъп до нея:

class A
include Mod
def foo(x)
super(x) + 1
end
end
A.new.foo(5) == 26 # true

class A
include Mod2
end
A.new.foo(5) == 11 # true

class A
include Mod
end
A.new.foo(5) == 11

0 за отговор № 3

Ruby намира super чрез търсене в предшествената верига на клас / модуледин клас / модул в даден момент, докато намери дефиницията на метода, който търси. Като автобус с много спирки, търсейки правилното място за слизане, но винаги се изключва при първата възможност. става докрай BasicObject и няма да го спре, че ще вдигне NoMethodError.

Когато включите модул, вие го добавяте към веригата на предците точно над включения клас / модул. Module.ancestorsМожете да включите същия модул многократно, но той ще бъде добавен само към веригата на предците. Помислете за това:

module Mod
def foo(x)
x**2
end
end

module Mod2
def foo(x)
x*2
end
end

class A
include Mod
def foo(x)
super(x) + 1
end
end

A.ancestors # => [A, Mod, Object, Kernel, BasicObject]

class A
include Mod2
def foo(x)
super(x) + 1
end
end

A.ancestors # => [A, Mod2, Mod, Object, Kernel, BasicObject]

class A
include Mod
def foo(x)
super(x) + 1
end
end

A.ancestors # => [A, Mod2, Mod, Object, Kernel, BasicObject]

Mod вече беше във веригата на родословието втори път, когато беше включен, така че нищо ново не се случи. Той остава сложен, и super все още удари Mod2 на първо място. Накратко, не можете да "замените" по-новите модули, като включите по-стари модули, които вече са били там. Има и други неща, които можете да направите. Mod3, или може би ModOverride, със същото определение за foo както беше в Mod и включете това или разгледайте уточненията Ruby 2.0 Как да се изключи модул от модул след неговото включване?

Странична бележка

Както отбелязват други отговори, не е необходимо да предефинирате A#foo всеки път, когато определението остава същото.