2014-08-29 6 views
0

Пожалуйста, помогите мне понять переменные экземпляра класса.Переменные экземпляра класса в Ruby

@@ - это переменная класса и эквивалентна переменной экземпляра (@) в экземпляре класса.

Но что такое переменная экземпляра (@) при использовании на уровне класса? Если он помещает определение в экземпляр класса, то почему бы не определить его в инициализаторе?

class MyClass 
    cattr_reader :class_variable 

    def self.new_instance(cv, cliv, iv) 
    @@class_variable = cv 
    @class_level_instance_variable = cliv 
    self.new(iv) 
    end 

    def initialize(iv) 
    @instance_variable = iv 
    end 

    def use 
    puts "class_var=#{self.class.class_variable.inspect}\ninst_var=#{@instance_variable.inspect}\ncliv=#{@class_level_instance_variable.inspect}" 
    end 
end 

c = [] 
c << MyClass.new_instance(1,2,3) 
c[0].use 
c << MyClass.new_instance(4,5,6) 
c[1].use 
c << MyClass.new_instance(7,8,9) 
c[2].use 

c[0].use 
c[1].use 
c[2].use 
+1

Когда вы задаете переменную экземпляра на уровне класса, она становится переменной экземпляра класса, которая немного отличается (и не является эквивалентной) переменной класса. Больше информации здесь: http://www.railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/ –

+0

@Marek Lipka: так, если бы я понял правильно, класс переменные экземпляра уровня полностью эквивалентны предварительно инициализированным переменным экземпляра экземпляра экземпляра, и если я делаю несколько экземпляров класса в методе класса, каждый из этих экземпляров будет инициализирован этой переменной. – Paul

+0

Нет, такого поведения вообще нет. Я имею в виду только переменную экземпляра класса, которая является переменной * regular * экземпляра, но привязана к объекту класса (помните, что в классах Ruby также есть объекты). –

ответ

2

В вашем ответе вы не выводите переменную экземпляра класса. Помимо обычного синтаксиса (@foo), переменную экземпляра можно получить с помощью метода (instance_variable_get(:@foo)). Этот метод можно использовать для чтения переменных экземпляра других объектов, а не только self.

Вот модифицированная версия кода

require 'active_support/core_ext' 

class MyClass 
    cattr_reader :class_variable 

    def self.new_instance(cv, cliv, iv) 
    @@class_variable = cv 
    @class_level_instance_variable = cliv 
    self.new(iv) 
    end 

    def initialize(iv) 
    @instance_variable = iv 
    end 

    def use 
    puts "class_var=#{self.class.class_variable.inspect}" 
    puts "class inst var: #{self.class.instance_variable_get(:@class_level_instance_variable)}" 
    puts "inst_var=#{@instance_variable.inspect}" 
    end 
end 

c = [] 
c << MyClass.new_instance(1,2,3) 
c << MyClass.new_instance(4,5,6) 
c << MyClass.new_instance(7,8,9) 

c[0].use 
c[1].use 
c[2].use 
# >> class_var=7 
# >> class inst var: 8 
# >> inst_var=3 
# >> class_var=7 
# >> class inst var: 8 
# >> inst_var=6 
# >> class_var=7 
# >> class inst var: 8 
# >> inst_var=9 

See, класс инст вар всегда 8 (так же, как класс вар всегда 7). Это связано с тем, что вы выводите значения после внесения всех изменений. А поскольку переменные уровня класса разделяются, выигрывает последняя модификация.

c << MyClass.new_instance(7,8,9) 

Если вы должны были вывести из инициализатора (как и в вашей первой версии кода), вы увидите разные результаты.

# >> class_var=1 
# >> class inst var: 2 
# >> inst_var=3 
# >> class_var=4 
# >> class inst var: 5 
# >> inst_var=6 
# >> class_var=7 
# >> class inst var: 8 
# >> inst_var=9 
+0

Итак, переменная экземпляра уровня класса дает возможность общаться между дочерними элементами, поскольку передается по ссылке на каждый экземпляр. Правильно? – Paul

+0

Да, он делится между всеми экземплярами класса. –

1

Надеюсь, этот пример объяснит разницу между переменными @ (instance) и @@ (class).

class Animal 
    @@total_count = 0 

    def self.total_count 
    @@total_count 
    end 

    def initialize 
    @@total_count += 1 
    end 
end 

class Cat < Animal 
end 

Animal.new 
Animal.new 
Cat.new 

Animal.total_count # => 3 
Cat.total_count # => 3 

Как вы видите, переменная @@ разделяется между классом и его дочерними элементами. Если я действительно хочу подсчитать количество экземпляров классов, я должен использовать следующий код.

class Animal 
    class << self 
    attr_accessor :total_count 
    end 

    @total_count = 0 

    def self.total_count 
    @total_count 
    end 

    def initialize 
    self.class.total_count += 1 
    end 
end 

class Cat < Animal 
    @total_count = 0 
end 

Animal.new 
Animal.new 
Cat.new 

Animal.total_count # => 2 
Cat.total_count # => 1 
Смежные вопросы