2012-05-15 3 views
1

я наткнулся на следующий пример из this tutorial:Переменные класса в Ruby,

class Song 
    @@plays = 0 

    def initialize(name, artist, duration) 
    @name = name 
    @artist = artist 
    @duration = duration 
    @plays = 0 
    end 

    def play 
    @plays += 1 
    @@plays += 1 
    "This song: #@plays plays. Total #@@plays plays." 
    end 
end 

s1 = Song.new("Song1", "Artist1", 234) # test songs 
s2 = Song.new("Song2", "Artist2", 345) 

puts s1.play 
puts s2.play 
puts s1.play 
puts s1.play 

Is @@ играет вежливо доступны только внутри класса Song? This commentary приводит к тому, что не рекомендуется использовать переменные класса. Является ли это b/c, что они часто не требуются для повседневного использования и создают много отладочных головных болей при их использовании?

ответ

-3

Переменная @@ будет переменной класса. Это, как правило, плохая практика. В вашем коде это избыточно, потому что @plays == @@ играет (если вы не установите @@ в другом месте вашего кода (плохая практика))

На самом деле теперь, когда я смотрю на это, они на самом деле не то же самое. @plays подсчитывает, сколько раз была воспроизведена отдельная песня, а @@ играет с подсчетом всех песен. Тем не менее, его, вероятно, неправильная практика использования @@ играет. Обычно у вас есть родительский класс, такой как «Player», который управляет всеми песнями. В классе «Player» должна быть переменная экземпляра, называемая @total_plays.

+0

Значит, @plays и @@ играют в этом случае точно идентичны? Я понимаю, почему плохая практика заключается в соединении точек между тем, что вы говорите, и статьей. – stanigator

+3

** Это неправильно **. '@@' - это переменная класса, а не глобальная переменная. '@ play' и' @@ играет' ** не ** то же самое. Вы также не разрабатываете вообще * почему * это может быть плохой практикой. –

+0

Согласен. посмотри мой ответ ниже – ctilley79

1

Переменная класса - это переменная, которая является общей для всех экземпляров класса. Это означает, что для всех объектов, созданных из этого класса, существует только одно значение переменной. Это означает, что если один экземпляр объекта изменит значение переменной, это новое значение существенно изменится для всех других экземпляров объекта. Другой способ мышления переменных класса - это глобальные переменные в контексте одного класса.

@@plays #is a class variable 
@plays #is an instance variable 
$plays #is a global variable accessed outside a class 

Итак, в вашем примере вы создали переменную класса @@, чтобы рассчитать общее количество песен, сыгранных для всех песен. Поскольку это переменная класса, к ней нельзя получить доступ только вне класса. Если вы хотите получить доступ к общему количеству пьес, вы можете использовать глобальную переменную. Они начинаются со знака доллара $ play (в вашем случае). Я предупреждаю вас, вы должны избегать использования глобальных переменных, поскольку они являются проблематичными по многим причинам. Одна вещь, которую вы можете рассмотреть, - создать метод, который выталкивает все экземпляры песен в массив. Затем вы можете суммировать все пьесы по всем песням через итераторы. Путь более безопасный, менее подверженный ошибкам программиста.

Edit: Вот почему глобальные переменные плохо

Are global variables bad?

17

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

Причина, по которой они рекомендованы, такова, как показано в этой статье, они действительно запутывают. В частности, переменные класса класса разделяются его подклассами и экземплярами его подклассов. Например:

class Parent 
end 

class Child1 < Parent 
    @@class_var = "Child1's" 
end 

class Child2 < Parent 
    @@class_var = "Child2's" 
end 

С этим кодом, Child1 и его экземпляры будут все видеть переменный класс с именем @@class_var со значением "Child1's" и Child2 и его экземпляры будут все видеть переменный класс с именем @@class_var со значением "Child2's". Но предположим, что в дальнейшем мы заново Родитель и написать следующее:

class Parent 
    @@class_var = "Parent's" 
end 

Теперь Родитель и экземпляры, которые он создает все увидим переменную класса с именем @@class_var со значением "Parent's". Но это еще не все.Теперь, когда родительский класс имеет эту переменную, Child1 и Child2 внезапно обмениваются переменной, поэтому все @@class_var s имеют значение "Parent's". И если вы переназначите переменную в Child1, она по-прежнему будет использоваться совместно, поэтому все классы будут обновлены. Как странно!

Вместо переменных классов, вы можете просто использовать переменный экземпляр класса, например:

class Parent 
    @class_var = "Parent's" 
    def self.class_var 
    @class_var 
    end 
end 

class Child1 < Parent 
    @class_var = "Child1's" 
end 

class Child2 < Parent 
    @class_var = "Child2's" 
end 

Теперь Parent.class_var вернется «Родитель», Child1.class_var вернется «Child1» и Child2.class_var вернется «Child2-х »- точно так же, как вы ожидаете.

+0

Это должно быть обязательно для всех новых рубистов. –

+0

Согласен, что этот материал действительно запутан, это приятное объяснение –