Чтение онлайн

на главную - закладки

Жанры

Программирование на языке Ruby
Шрифт:

str = "PI"

Math.const_get(str) # Значение равно Math::PI.

Это способ избежать обращения к методу

eval
, которое иногда считается неэлегантным. Такой подход дешевле с точки зрения потребления ресурсов и безопаснее. Есть и другие аналогичные методы:
instance_variable_set
,
instance_variable_get
и
define_method
.

Метод

const_get
действительно работает быстрее, чем
eval
. В неформальных тестах — на 350%
быстрее, хотя у вас может получиться другой результат. Но так ли это важно? Ведь в тестовой программе на 10 миллионов итераций цикла все равно ушло менее 30 секунд.

Истинная полезность метода

const_get
в том, что его проще читать, он более специфичен и лучше самодокументирован. Даже если бы он был всего лишь синонимом
eval
, все равно это стало бы большим шагом вперед.

11.3.3. Динамическое создание экземпляра класса, заданного своим именем

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

Правильный способ — воспользоваться методом

const_get
, который мы только что рассмотрели. Имена всех классов в Ruby — константы в «глобальном» пространстве имен, то есть члены класса
Object
.

classname = "Array"

klass = Object.const_get(classname)

x = klass.new(4, 1) # [1, 1, 1, 1]

А если имена вложены? Как выясняется, следующий код не работает:

class Alpha

 class Beta

class Gamma

FOOBAR =237

end

 end

end

str = "Alpha::Beta::Gamma::FOOBAR"

val = Object.const_get(str) # Ошибка!

Дело в том, что метод

const_get
недостаточно «умен», чтобы распознать такие вложенные имена. Впрочем, в следующем примере приведена работающая идиома:

# Структура класса та же

str = "Alpha::Beta::Gamma::FOOBAR"

val = str.split("::").inject(Object) {|x,y| x.const_get(y) } # 237

Такой код встречается часто (и демонстрирует интересное применение

inject
).

11.3.4. Получение и установка переменных экземпляра

Отвечая на пожелание употреблять

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

class MyClass

 attr_reader :alpha, :beta

 def initialize(a,b,g)

@alpha, @beta, @gamma = a, b, g

 end

end

x = MyClass.new(10,11,12)

x.instance_variable_set("@alpha",234)

p x.alpha # 234

x.instance_variable_set("@gamma",345) # 345

v = x.instance_variable_get("@gamma") # 345

Прежде

всего, отметим, что имя переменной должно начинаться со знака
@
, иначе произойдет ошибка. Если это кажется вам неочевидным, вспомните, что метод
attr_accessor
(и ему подобные) принимает для формирования имени метода символ, поэтому-то знак
@
и опускается.

Не нарушает ли существование таких методов принцип инкапсуляции? Нет. Конечно, эти методы потенциально опасны. Пользоваться ими следует с осторожностью, а не при всяком удобном случае. Но нельзя говорить, что инкапсуляция нарушена, не видя, как эти инструменты применяются в конкретном случае. Если это делается обдуманно, ради ясно осознанной цели, то все хорошо. Если же цель состоит в том, чтобы нарушить проект или обойти неудачное проектное решение, это печально. Ruby намеренно предоставляет доступ к внутренним деталям объектов тем, кому это действительно нужно; ответственный программист не станет пользоваться свободой во вред.

11.3.5. Метод define_method

Помимо ключевого слова

def
, единственный нормальный способ добавить метод в класс или объект — воспользоваться методом
define_method
, причем он позволяет сделать это во время выполнения.

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

puts
, как в примере ниже, вы это сами увидите.

class MyClass

 puts "до"

 def meth

#...

 end

 puts "после"

end

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

eval
, теперь же у нас есть метод
define_method
. Он принимает символ (имя метода) и блок (тело метода).

Первая (ошибочная) попытка воспользоваться этим методом могла бы выглядеть так:

# Не работает, так как метод define_method закрытый.

if today =~ /Saturday | Sunday/

 define_method(:activity) { puts "Отдыхаем!" }

else

 define_method(:activity) { puts "Работаем!" }

end

activity

Поскольку

define_method
— закрытый метод, приходится поступать так:

Поделиться:
Популярные книги

Кодекс Охотника. Книга VI

Винокуров Юрий
6. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга VI

Газлайтер. Том 16

Володин Григорий Григорьевич
16. История Телепата
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Газлайтер. Том 16

Сильнейший Столп Империи. Книга 5

Ермоленков Алексей
5. Сильнейший Столп Империи
Фантастика:
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Сильнейший Столп Империи. Книга 5

Поход

Валериев Игорь
4. Ермак
Фантастика:
боевая фантастика
альтернативная история
6.25
рейтинг книги
Поход

Идеальный мир для Лекаря 26

Сапфир Олег
26. Лекарь
Фантастика:
аниме
фэнтези
5.00
рейтинг книги
Идеальный мир для Лекаря 26

Геном хищника. Книга четвертая

Гарцевич Евгений Александрович
4. Я - Легенда!
Фантастика:
боевая фантастика
рпг
попаданцы
5.00
рейтинг книги
Геном хищника. Книга четвертая

Казачий князь

Трофимов Ерофей
5. Шатун
Фантастика:
боевая фантастика
попаданцы
альтернативная история
5.00
рейтинг книги
Казачий князь

Печать зверя

Кас Маркус
7. Артефактор
Фантастика:
городское фэнтези
аниме
5.00
рейтинг книги
Печать зверя

Камень. Книга 4

Минин Станислав
4. Камень
Фантастика:
боевая фантастика
7.77
рейтинг книги
Камень. Книга 4

Бездна

Кораблев Родион
21. Другая сторона
Фантастика:
боевая фантастика
рпг
уся
попаданцы
5.00
рейтинг книги
Бездна

По осколкам твоего сердца

Джейн Анна
2. Хулиган и новенькая
Любовные романы:
современные любовные романы
5.56
рейтинг книги
По осколкам твоего сердца

Лейб-хирург

Дроздов Анатолий Федорович
2. Зауряд-врач
Фантастика:
альтернативная история
7.34
рейтинг книги
Лейб-хирург

Страж Кодекса. Книга IV

Романов Илья Николаевич
4. КО: Страж Кодекса
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Страж Кодекса. Книга IV

Путь одиночки. Книга 2

Понарошку Евгений
2. Одиночка
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Путь одиночки. Книга 2