2015-07-09 4 views
3

Вот мой код:модуля методы в Рубине

module Star 
    def Star.line 
    puts '*' * 20 
    end 
end 

module Dollar 
    def Star.line 
    puts '$' * 20 
    end 
end 

module At 
    def line 
    puts '@' * 20 
    end 
end 

include At 
Dollar::line # => "@@@@@@@@@@@@@@@@@@@@" 
Star::line # => "$$$$$$$$$$$$$$$$$$$$" 
Dollar::line # => "@@@@@@@@@@@@@@@@@@@@" 
line   # => "@@@@@@@@@@@@@@@@@@@@" 

Может кто-нибудь объяснить, как я получаю этот результат? Я не понимаю поток поиска метода здесь.

ответ

7

Вот как я это вижу:

Dollar::line

Там нет такого метода, определенного в этом модуле, так это звонит At::line, потому что вы включили этот модуль.

Star::line

Он использует последний из определения Dollar модуля (она идет после первоначального определения Star поэтому он переопределен).

Dollar::line

Третий вызов является такой же, как и первый.

line

И последний из At::line, потому что Вы сделали включаемый.

+5

Почти. Ваши объяснения верны: 'include' на верхнем уровне включает в себя' Object', а с 'Dollar.is_a? (Object)' вы можете вызывать любой метод, который определен в 'Object' или смешанный в' Object', включая 'At # line'. Однако 'line' в' At' - это метод экземпляра ('At # line'), а не функция модуля (' At :: line'), и именно поэтому это работает. –

+0

@ JörgWMittag Спасибо!Ваше понимание объектов Module/include/Object является способом глубже, чем у меня) –

1

Является

module Dollar 
    def Star.line 

намеренным или опечатка?

Похоже, что Dollar.line не определен, и вместо этого используется метод line в At.

+0

Это не дает ответа на вопрос. Чтобы критиковать или просить разъяснения у автора, оставьте комментарий ниже их сообщения. –

+0

Ну, вопрос был: «Может кто-нибудь объяснить, как я получаю этот результат?». Мой ответ: «Похоже, что Dollar.line не определен, и вместо этого используется строка метода в At». Что в этом плохого? Во всяком случае, я уже поддержал объяснение @MaximPontyushenko, которое намного более исчерпывающее, чем мое :-) –

+1

Вы правы, мой комментарий выглядит некорректно (проголосовали +1 за ваш ответ). –

1

Сначала вам нужно понять, что Ruby ищет константы, несколько похожие на методы. Он начинается с поиска константы в текущем лексическом диапазоне . Если он не найдет константу, она поднимается на один уровень и смотрит туда и т. Д. Если он не может найти постоянную нигде, он в конечном итоге ищет верхний уровень, поэтому вы можете получать доступ к модулям, например Kernel, из любого места вашего кода.

module Star 
end 
Star.object_id # 20 

module Dollar 
    Star.object_id # 20. No Star in current scope, so gets the top-level star 
end 

module At 
    module Star 
    end 
    Star.object_id # 10. There is now a Star in this scope, so we don't get the top-level one 
end 

Следующая вещь, чтобы понять, что методы, определенные на верхнем уровне в Ruby, сделаны экземпляр методы Object. Поскольку все в Ruby является экземпляром Object, такие методы всегда можно вызвать.

Наконец, рассмотрим, что делает include: он принимает методы экземпляра из модуля и делает их экземплярами методов в текущей области. Так что если вы include что-то на верхнем уровне, все эти методы добавляются в Object!

Таким образом, ваш код, по существу, эквивалентно следующему:

module Star 
    def self.line 
    puts '*' * 20 
    end 

    # this overwrites the previous definition 
    def self.line 
    puts '$' * 20 
    end 
end 

# because of the way constants are looked up, the def ends up in Star 
module Dollar 
end 

module At 
    def line 
    puts '@' * 20 
    end 
end 

# the include does this, so now every object (including Dollar) can call line 
def line 
    puts '@' * 20 
end 

# except Star already has its own line method, so the one from Object won't be called for it 
Star.line # "$$$$$$$$$$$$$$$$$$$$" 
Смежные вопросы