2012-02-16 5 views
35

Я очень новичок в ruby ​​(я на самом деле C# dev.), Поэтому этот вопрос может быть noob. У меня есть класс, как показано ниже, и я использовал переменные экземпляра (массив), чтобы избежать использования множества параметров метода.Использование переменных экземпляра в методах класса - Ruby

Работает так, как я ожидал, но это хорошая практика? На самом деле я бы не ожидал, что это сработает, но я думаю, что методы класса не работают как статические методы на других языках, поэтому мне интересно, является ли это хорошей практикой или я могу столкнуться с такими проблемами, как действие этих переменных как переменных класса и все испортить.

class DummyClass 
    def self.dummy_method1 
    @arr = [] 
    # Play with that array 
    end 

    def self.dummy_method2 
    # use @arr for something else 
    end 
end 

ответ

58

Приведенные переменные экземпляра причины для классов в Ruby состоят в том, что классы Ruby являются самими (экземпляры класса Class). Попробуйте сами, проверив DummyClass.class. В языке C# в Ruby нет «статических методов», потому что каждый метод определен (или унаследован) каким-то экземпляром и вызывается в каком-то экземпляре. Соответственно, они могут получить доступ к любым переменным экземпляра, которые будут доступны для вызываемого абонента.

С DummyClass - это экземпляр, он может иметь свои собственные переменные экземпляра просто отлично. Вы даже можете получить доступ к этим переменным экземпляра, если у вас есть ссылка на класс (который всегда должен быть указан потому, что имена классов являются константами). В любой момент вы сможете вызвать ::DummyClass.instance_variable_get(:@arr) и получить текущее значение этой переменной экземпляра.

Что касается того, хорошо ли это делать, зависит от методов.

Если @arr логически является «состоянием» экземпляра/класса DummyClass, то сохраните его в переменной экземпляра. Если @arr используется только в dummy_method2 в качестве оперативного ярлыка, передайте его в качестве аргумента. Чтобы привести пример использования подхода с переменной экземпляра, рассмотрите ActiveRecord в Rails. Это позволяет сделать это:

u = User.new 
u.name = "foobar" 
u.save 

Здесь имя, которое было назначено пользователю данные, что законно на пользователя. Если перед вызовом #save нужно было спросить «какое имя пользователя на этом этапе», вы ответите «foobar». Если вы копаете достаточно далеко во внутренностях (вы будете копать очень далеко и много метапрограммировать, вы обнаружите, что они используют переменные экземпляра именно для этого).

Пример, который я использовал, содержит два отдельных публичных вызова. Чтобы увидеть случай, когда переменные экземпляра все еще используются, несмотря на только один сделанный вызов, посмотрите на реализацию ActiveRecord #update_attributes. Тело метода просто load(attributes, false) && save.Почему #save не получает никаких аргументов (например, новый name), хотя он будет находиться в теле, где-то вроде UPDATE users SET name='foobar' WHERE id=1;? Это потому, что такие вещи, как имя, являются информацией, которая принадлежит экземпляру.

И наоборот, мы можем посмотреть на случай, когда переменные экземпляра не имеют смысла использовать. Посмотрите на реализацию #link_to_if, метод, который принимает аргумент boolean-ish (обычно это выражение в исходном коде) вместе с аргументами, которые обычно принимаются #link_to, например URL-адрес для ссылки. Когда логическое условие является правдивым, необходимо передать остальные аргументы #link_to и вызвать его. Было бы нецелесообразно назначать переменные экземпляра здесь, потому что вы не сказали бы, что вызывающий контекст здесь (средство визуализации) содержит эту информацию в экземпляре. В самом рендерере нет «ссылки для ссылки», и, следовательно, он не должен быть похоронен в переменной экземпляра.

+1

Благодарим вас за это замечательное объяснение примерами, особенно о том, является ли это хорошей практикой или нет. – tackleberry

16

Тот экземпляр класса переменные и являются совершенно законными вещами в рубине: классы объекты тоже (экземпляры класса) и поэтому имеют переменный экземпляр.

Одна вещь, чтобы высматривать в том, что каждый подкласс будет иметь свой собственный набор экземпляров классов переменных (все-таки это разные объекты): Если вы подклассы DummyClass, методы класса на подкласс не сможет увидеть @arr.

Переменные класса (@@foo), конечно, наоборот: вся иерархия классов разделяет одни и те же переменные класса.

+0

hmm thats something different. Так что об этом ничего не беспокоиться, пока я не наследую новый класс. Это хорошие новости, спасибо! – tackleberry

Смежные вопросы