2016-12-07 5 views
2

class_eval и instance_eval вполне предсказуемы в таких случаях, как методы определения. Я также понимаю разницу между экземпляром класса и синглэтом класса (aka eigenclass).Глубоко в Ruby class_eval и instance_eval

НО

Я не могу понять единственную вещь, как следующее: Скажем, для некоторых Strage целей, мы хотим, чтобы сделать существующий класс быть синглтон.

class A; end 
class B; end 

A.class_eval do 
    private :new 
end 

B.instance_eval do 
    private :new 
end 

в обеих случаях получил

NameError: undefined method 'new' for class 
Did you mean? new 

да, я имею в виду именно этот метод.

Кроме того, эти два варианта дают тот же результат, как и self точек на объект класса в обоих случаях

A.class_eval do 
    class << self 
    private :new 
    end 
end 

A.new 
=> NoMethodError: private method 'new' called for A:Class 

B.instance_eval do 
    class << self 
    private :new 
    end 
end 

B.new 
=> NoMethodError: private method 'new' called for B:Class 

Каким образом? Может ли кто-нибудь пролить свет на это?

+0

'new' в классах в Ruby фактически определяется с помощью' initialize'. Попробуйте заменить ': new' на': initialize' – casraf

+0

@casraf Неправильно. 'new' определяется классом (суперкласс всех классов) и выполняет две функции (из [docs] (https://ruby-doc.org/core-2.3.1/Class.html#method-c-new)): «Вызывает' allocate' для создания нового объекта класса * class *, затем вызывает этот метод 'initialize' объекта, передавая его * args *. Это метод, который заканчивается тем, что получает вызов, когда объект построен используя .new. " Когда вы определяете (переопределяете) 'initialize' в классе, он не определяет или не изменяет' new', а 'new' может быть переопределен, как любой другой метод класса (хотя я не могу придумать причину). –

+0

Мой плохой. Спасибо за разъяснения :) – casraf

ответ

0

Давайте заглянуть в то, что само здесь:

class A 
    puts self.inspect 

    class << self 
    puts self.inspect 
    end 
end 

A.class_eval { 
    puts self.inspect 

    class << self 
    puts self.inspect 
    end 
} 

A.instance_eval{ 
    puts self.inspect 

    class << self 
    puts self.inspect 
    end 
} 

Мы получаем следующий вывод:

A 
#<Class:A> 
A 
#<Class:A> 
A 
#<Class:A> 

class_eval метод определен для модулей (и, таким образом классы) и оценивает в пределах контекст модуля (класса). Метод instance_eval оценивается в контексте объекта BasicObject. Кажется, что в этих случаях два (три фактически) - одно и то же.

Однако, я знаю, что если методы создали внутри блока eval, то class_eval создает методы экземпляра, а instance_eval создает методы класса. Уже есть отличная публикация для этого наблюдения:

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

  • Нет связанных вопросов^_^