2016-12-28 7 views
-1

Каким образом, если у меня есть класс, как:Почему я получаю неопределенную локальную переменную или ошибку метода при использовании константы, но не при использовании метода?

class Thing 
    def number 
    10 
    end 
end 

И я наследовать от него, как это:

class OtherThing < Thing 
    CONSTANT = number/2 
end 

Я получаю undefined local variable or method 'number', когда я пытаюсь создать экземпляр класса, но если я делаю это:

class OtherThing < Thing 
    def method_instead_of_constant 
     number/2 
    end 
    end 

Это работает?

EDIT

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

+3

Читайте о 'self' в Ruby ... это вам очень поможет. –

ответ

2

Вам нужен метод класса для достижения функциональности вы ищете:

class Thing 
    # ⇓⇓⇓⇓ HERE 
    def self.number 
    10 
    end 
end 

class OtherThing < Thing 
    CONSTANT = number/2 
end 

CONSTANT назначения происходит на уровне класса, следовательно, он имеет доступ к методам класса в Thing, но не к экземпляру его методов.

С другой стороны, вы можете создать экземпляр Thing, а затем вызвать метод экземпляра на нем:

class Thing 
    def number 
    10 
    end 
end 

class OtherThing < Thing 
    #   ⇓⇓⇓⇓⇓⇓⇓⇓⇓ HERE 
    CONSTANT = Thing.new.number/2 
end 
+0

Я не думаю, что конечной целью является определение такой постоянной. Это просто иллюстрация к «это работает, это не так» –

+0

Или, может быть, это так. Кто знает :) –

+0

@SergioTulentsev Да, я просто бросил два примера, показывая «что работает, что нет» :) – mudasobwa

3

Потому что number является методом экземпляра на Thing. Объем определения класса OtherThing является экземпляром Class, что означает, что он не является экземпляром Thing или экземпляром OtherThing при определении.

Таким образом, вы не должны определять константы путем выполнения методов. Вероятно, вы можете иметь вычисленную переменную класса, которую вы вызываете freeze, чтобы предотвратить редактирование после запуска, но даже это не очень общий шаблон.

1

Из-за объема.

Вызовы методов оцениваются на основе динамической области и различают класс и область экземпляра. Константы разрешаются в лексической области и не различают класс и область экземпляра, как это делают методы.

class A 
    # expressions are evaluated in scope of class A 
    def m 
    # expressions are evaluated in scope of an instance of A 
    return 42 
    end 
end 

Класс и пример не совпадают.

A 
a = A.new 

A.class # => Class 
a.class # => A 

A.respond_to?(:m) # => false 
a.respond_to?(:m) # => true 

A.m # => raises NoMethodError 
a.m # => 42 

Следовательно, в классе класса вы не можете вызвать методы экземпляра.

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

module M 
    # can access global constants and those defined in M 
    class A 
    # can access global constants and those defined in M or A 
    def m 
     # can access global constants and those defined in M or A 
    end 
    end 
end 

Вы можете проверить текущий постоянный путь подстановок с Module.nesting

1

Я не обязательно ищу хак, чтобы сделать эту работу, но и [так] понимание, почему это Безразлично» т.

Вот сообщение об ошибке:

undefined local variable or method 'number' 

Когда интерпретатор Руби видит number он ищет локальную переменную или метод с именем number. В контексте метода интерпретатор считывает number как self.number. Так эта линия:

CONSTANT = number/2 

фактически рассматривается как:

CONSTANT = self.number/2 

Так что self?

Ну, это зависит от того, где вы его определили (явно или неявно). В блоке класса self является самим классом, то есть OtherThing. Поскольку OtherThing ни один из его предков не имеет класса-метода number и не существует переменной number, Ruby выдает сообщение об ошибке.

self, определенный в определении метода экземпляра, является текущим объектом. Но это ужасно абстрактно без примеров и некоторой теории. Другие актуальные темы: Singleton-Classes и Наследование. Если вам нравятся книги, я рекомендую The Well-Grounded Rubyist 2nd Ed, Chapter 5 от David A. Black. Поразмыслив, прочитайте/изучите всю книгу.