В Ruby, в контекста на метод на клас, какво са променливи на екземпляр и клас?

Ако имам следната част от кода на Ruby:

class Blah
  def self.bleh
    @blih = "Hello"
    @@bloh = "World"
  end
end

Какво точно са @blih и @@bloh? @blih е променлива на екземпляр в класа Blah, а @@bloh е променлива на класа в класа Blah, нали? Това означава ли, че @@bloh е променлива в класа на Blah, Class?


person pupeno    schedule 08.04.2010    source източник


Отговори (4)


Хората изглежда игнорират, че методът е класов метод.

@blih ще бъде променлива на екземпляра на класа Class за константата Bleh. Следователно:

irb(main):001:0> class Bleh
irb(main):002:1>   def self.bleh
irb(main):003:2>     @blih = "Hello"
irb(main):004:2>     @@blah = "World"
irb(main):005:2>   end
irb(main):006:1> end
=> nil
irb(main):007:0> Bleh.instance_variables
=> []
irb(main):008:0> Bleh.bleh
=> "World"
irb(main):009:0> Bleh.instance_variables
=> ["@blih"]
irb(main):010:0> Bleh.instance_variable_get :@blih
=> "Hello"

@@blah ще бъде достъпен като класова променлива на Bleh:

irb(main):017:0> Bleh.class_variables
=> ["@@blah"]
irb(main):018:0> Bleh.send :class_variable_get, :@@blah
=> "World"
person user253455    schedule 08.04.2010

Има метод за тази лудост...

class Example
  @foo # class instance variable
  @@bar # class variable

  def fun1
    @baz # instance variable
  end
end

Променливи на екземпляра

Променливите на екземпляра (@foo и @baz в примера) винаги започват с @ и те винаги принадлежат на независимо от обекта, към който се отнася: или обект от класа, или класа обект, представляващ клас. Препратка към променлива на екземпляр в дефиниция на клас или метод на клас е напълно различна от препратка към променлива на екземпляр в метод на екземпляр.

Наследяване
Тъй като променливите на екземпляра не са дефинирани от клас, те не са свързани с механизма за наследяване — те просто се създават, когато им се присвои стойност. Следователно променливите на екземпляра на класа, които са просто променливи на екземпляра на обекта Class, който представлява клас, не се наследяват.

Променливи на класа

Променливите на класа са видими и споделени от методите на класа и методите на екземпляра на класа, а също и от самата дефиниция на класа. Променливите на класа могат да се използват в методи на екземпляр, методи на клас и в самата дефиниция на клас, извън всеки метод. Променливите на класа винаги се оценяват по отношение на обекта на класа, създаден от включващия оператор за дефиниция на клас.

Променлива на екземпляр на клас срещу променлива на екземпляр

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

Голяма част от това е от отличния "Езикът за програмиране Ruby"
алтернативен текст

person JRL    schedule 08.04.2010
comment
@banister: Склонен съм да не се съглася. Мисля, че конкретно отговорих на въпроса с двете изречения, които са удебелени. Можех просто да поставя тези твърдения без останалите, но мисля, че щеше да е по-малко полезно. Както и да е, това е само моето мнение. - person JRL; 08.04.2010

Променлива с префикс два знака at е променлива на класа, достъпна както в методите на екземпляра, така и в класа на класа.

Пример:

class CountEm
  @@children = 0

  def initialize
    @@children += 1
    @myNumber = @@children
  end

  def whoAmI
    "I'm child number #@myNumber (out of #@@children)"
  end

  def CountEm.totalChildren
    @@children
  end
end

c1 = CountEm.new
c2 = CountEm.new
c3 = CountEm.new
c1.whoAmI              # -> "I'm child number 1 (out of 3)"
c3.whoAmI              # -> "I'm child number 3 (out of 3)"
CountEm.totalChildren  # -> 3

Пример, взет от текст на връзката

person Petros    schedule 08.04.2010
comment
OP разбира какви са променливите на класа, той пита как могат да се променят, когато се използват от метод на клас. - person Jimmy; 08.04.2010
comment
Не съм сигурен, но ако случаят е такъв, тогава се извинявам. Моя грешка. - person Petros; 08.04.2010

[редактирано за яснота]

Във вашата примерна настройка @blih няма да се вижда извън обхвата на вашия метод на клас, защото вътре в метод на клас няма екземпляр, който да обвърже променлива на екземпляр към него.

Говорейки за терминология, бих казал „@@bloh е променлива на клас в клас Blah“, но не и „променлива в класа на Blah Class“. Клас "Клас" остава недокоснат.

person Wojciech Kaczmarek    schedule 08.04.2010
comment
Има екземпляр за прикачване. Класът е екземпляр на класа Class и ще бъде създаден, когато дефиницията на класа бъде оценена. › Bleh.instance_of? Клас =› вярно - person user253455; 08.04.2010
comment
crudson е правилен, @blih е променлива на екземпляр, прикрепена към класа Blah. - person horseyguy; 08.04.2010