2013-03-07 3 views
1

Я новичок в рубине и программировании в целом и стараюсь понять несколько ключевых концепций. Учитывая, что у меня есть собака класса, с нижеприведенными характеристиками.Ruby/Rails: понимание методов и экземпляров ruby ​​getter-setter

class Dog 
    attr_accessor :type, :popularity, :total 

    def initialize(type = nil) 
    @type = type 
    end 

    def total_dogs 
    Dog.count 
    end 

    def total 
    Dog.where(:type => self.type).size 
    end 

    def popularity 
    total.to_f/total_dogs 
    end 
end 

То, что я пытаюсь понять, как рубин сохраняется атрибуты экземпляра с помощью методов геттер/сеттер. Его для меня ясно, что если я создаю экземпляр нового экземпляра, а затем сохранить атрибуты этого экземпляра, эти атрибуты привязаны к этому экземпляру, потому что, если я смотрю на объект, атрибуты появляются в качестве таковых:

@dog = Dog.new 
@dog 
=> #<Dog:0x007fa8689ea238 @type=nil> 

Его легко для меня чтобы понять, что при передаче объекта @dog вокруг его всегда будет атрибут @type как нуль. Однако ситуация, с которой я столкнулся с проблемой, - это передать этот объект @dog другому классу. Как если бы я сделал:

Owner.new(@dog) 

Когда я нахожусь в классе владельца и я называю @ dog.popularity, как это известно значение популярности для этого экземпляра? Во время выполнения обрабатываются все методы, и тогда этот экземпляр всегда привязан к значению в то время? Извиняюсь, если это не имеет смысла или я ухожу.

ответ

6

Когда вы

@dog = Dog.new 

Вы делаете две spearate вещи

1) Создайте переменную @dog экземпляра для любого объекта, код в настоящее время внутри

2) Инстанцировать новый экземпляр Dog (со всеми его атрибутами и методами) и присвоить ссылку на него, чтобы @dog

@ dog - это переменная, которая просто указывает на экземпляр Dog («экземпляр класса», как правило, то же самое, что и «объект»), который вы создали в этот момент. Вы можете установить другие переменные, указывающие на один и тот же экземпляр, и в Ruby это, как правило, вы передаете данные. Объекты содержат переменные экземпляра, и эти переменные экземпляра указывают на еще большее количество объектов.

Используя оператор присваивания (i.e "="), вы можете указать переменную на любом другом объекте.

Чтобы ответить на ваши вопросы, в свою очередь:

Когда я нахожусь в классе владельца и я называю @ dog.popularity как это знать значение популярности для этого экземпляра?

Вы должны быть осторожны в Ruby (и языках OO в целом), чтобы различать класс и объект в описаниях и вопросах. Ruby Я предполагаю, что вы имеете в виду строку кода в классе Owner, и вы намерены работать с объектом владельца. Я также предполагаю, что @dog - это атрибут, который вы добавили в Owner.

В этом случае Ruby знает, потому что @dog указывает на объект Dog, который вы добавили владельцу. Каждый объект Dog имеет свою собственную копию всех переменных экземпляра Dog. Однако вам нужно позаботиться о Ruby, потому что переменные указывают на объекты, что вы не просто передаете один и тот же объект Dog всем владельцам (т. Е. Все они эффективно используют одну собаку). Поэтому вам нужно понять, когда вы создаете новые экземпляры (через новые) и когда вы просто обрабатываете существующие ссылки.

Во время выполнения все методы обрабатываются, а затем этот экземпляр только всегда привязан к значению в то время?

№ Во время выполнения базовый Ruby выполняет только присвоенные вами задания. Переменные экземпляра могут даже существовать до тех пор, пока не будет запущен код, который их назначает. Если вы используете методы attr_reader и т. Д., Тогда переменные будут, по крайней мере, существовать (но будут отсутствовать, если вы не назначили что-то во время инициализации)

+0

А, хорошо, спасибо вам большое. Поэтому в моем примере, когда создается экземпляр собаки, он получает свои значения при инициализации и всех своих методах. Однако методы не оцениваются до тех пор, пока приложение/программа не попросит его с чем-то вроде @ dog.popularity ... это значение, которое метод популярности возвращает, затем связанный с этим экземпляром собаки? например, если я снова его вызову, он снова обработает метод/связанные методы или он просто узнает значение с того момента, когда он был ранее вызван? – BC00

+0

Он обрабатывается каждый раз, он не помнит. Кстати, вы обычно не хотите или не нуждаетесь в «attr_accessor: foo» и «def foo» - только один или другой. Если все, что вы хотите, это чтение и запись переменных экземпляра, то attr_accessor прост. Что-то более сложное, вы хотите определить метод. –

+0

Огромная благодарность, это приносит много вещей для меня – BC00

0

При создании объекта вам не нужно использовать символ @. Переменной является объект. Так что если у вас есть несколько собак, вы могли бы сделать:

myDog = Dog.new(brown) 
yourDog = Dog.new(white) 

От там, вы можете сказать:

yourDog.type #white 
myDog.type #brown 

Что вы бы не сделать:

@dog = Dog.new #myDog 
@dog = Dog.new #yourDog 

Если вам нужно несколько версий объекта, вы просто даете им разные имена. Поэтому, если вы создаете несколько собак и передаете их другим объектам, они будут работать. Например:

Скажите ваш класс Владелец:

Class Owner 
def initialize(pet) 
    puts "my pet is #{pet.type}" 
end 

Затем с помощью переменной экземпляра будет:

me = Owner.new(myDog) #my pet is brown 
you = Owner.new(yourDog) #my pet is white 
0

Оба типа и популярность являются методами на «собачьих» экземплярах. Их определение выглядит следующим образом:

class Dog 
    # getter 
    def type 
    @type 
    end 

    def popularity 
    total.to_f/total_dogs 
    end 
end 

Это примерно эквивалентно:

class Dog 
    attr_accessor :type 

    def popularity 
    total.to_f/total_dogs 
    end 
end 

Обратите внимание, что attr_accessor это просто ярлык для определения метода геттер. Если вы определяете метод себя бессмысленно использовать attr_accessor:

class Dog 
    attr_accessor :popularity 

    # this will override getter defined by attr_accessor 
    def popularity 
    total.to_f/total_dogs 
    end 
end 

Вернуться на ваш вопрос: @ dog.type вызывает метод типа на @dog, который возвращает свой переменный экземпляр; @ dog.popularity вызывает метод популярности на @dog, который выполняет вычисления (как определено вами) на лету и возвращает результат. Здесь нет волшебства!

2

Ниль имеет отличный ответ для этого, я просто хочу что-то добавить к нему.

счетные Собаки :)

Вам нужна переменная класса, чтобы сделать это ..

class Dog 
    @@count = 0  # this is a class variable; all objects created by this class share it 

    def initialize 
    @@count += 1 # when we create a new Dog, we increment the count 
    end 
    def total 
    @@count 
    end 
end 

Существует еще один способ сделать это с «переменными экземпляра объекта класса», но это бит расширенной темы.

Доступ Переменные экземпляра

В Ruby переменные действительно только ссылки на объекты/экземпляры.

> x = 1 
=> 1 
> x.class 
=> Fixnum 
    > 1.instance_variables 
=> [] 

x является ссылкой на объект '1', который является экземпляром класса Fixnum. Объект '1' является экземпляром Fixnum, который не содержит переменных экземпляра. Это ничем не отличается от ссылки на новый экземпляр «Собака».

Аналогично, вы можете сказать x = Dog.new, тогда x является ссылкой на экземпляр класса Dog.

class Dog 
    attr_accessor :legs # this defines the 'legs' and 'legs=' methods! 
end 

x = Dog.new 
x.instance_variables 
=> []  # if you would assign legs=4 during "initialize", then it would show up here 
x.legs = 4  # this is really a method call(!) to the 'legs' method 
x.instance_variables # get created when they are first assigned a value 
=> [:legs] 

Это не имеет значения, если вы передаете такую ​​ссылку на вызов метода или к другому классу или просто оценить его сам по себе - Руби знает, что это ссылка на объект, и выглядит внутри объекта, и это цепочка наследования на как разрешать вещи.

Разрешающих Названия методов

Это было только частичная правда :) При интерпретации x.legs, Ruby проверяет, есть ли метод в классе-цепочке наследования объекта, который реагирует на это имя «ногу» , Это не волшебный доступ к переменной экземпляра с тем же именем!

Мы можем определить метод «ноги», выполнив «attr_reader: legs» или «attr_accessor: legs» или определяя метод самостоятельно.

class Dog 
    def legs 
    4  # most dogs have 4 legs, we don't need a variable for that 
    end 
end 

x.legs  # this is a method call! it is not directly accessing a :legs instance variable! 
=> 4 
x.instance_variables 
=> []  # there is no instance variable with name ":legs" 

и если мы пытаемся реализовать его в качестве метода и переменной экземпляра, это происходит: :)

class Dog 
    attr_accessor :legs # this creates "def legs" and "def legs=" methods behind the scenes 
    def legs  # here we explicitly override the "def legs" method from the line above. 
     4 
    end 
end 

x = Dog.new 
x.legs  # that's the method call we implemented explicitly 
=> 4 
x.legs = 3 # we can still assign something to the instance_variable via legs= 
=> 3 
x.legs  # the last definition of a method overrides previous definitions 
      # e.g. it overrides the automatically generated "legs" method 
=> 4 

attr_accessor :legs находится в нескольких минутах рука нотация для этого:

class Dog 
    def legs 
    @legs 
    end 
    def legs=(value) 
    @legs = value 
    end 
end 

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

Надеюсь, это имеет смысл для вас

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