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

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

Жанры

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

 #...

end

class Martian < IntelligentLife

 @@home_planet = "Mars"

 #...

end

Но это работать не будет. Вызов

Terran.home_planet
напечатает не
"Earth"
, а
"Mars"
! Почему так? Дело в том, что переменные класса — на практике не вполне переменные класса; они принадлежат не одному классу, а всей иерархии наследования. Переменная класса не копируется из родительского класса, а разделяется родителем (и, стало быть, со всеми братьями).

Можно было бы вынести определение переменной класса в базовый класс, но тогда перестали бы работать определенные нами методы класса! Можно было исправить и это, перенеся определения в дочерние классы, однако тем самым губится первоначальная идея, ведь таким образом объявляются отдельные классы без какой бы то ни было «параметризации».

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

class_eval
. Полное решение приведено в листинге 11.13.

Листинг 11.13. Параметрические классы: улучшенное решение

class IntelligentLife

 def IntelligentLife.home_planet

class_eval("@@home_planet")

 end

 def IntelligentLife.home_planet=(x)

class_eval("@@home_planet = #{x}")

 end

 # ...

end

class Terran < IntelligentLife

 @@home_planet = "Earth"

 # ...

end

class Martian < IntelligentLife

 @@home_planet = "Mars"

 # ...

end

puts Terran.home_planet # Earth

puts Martian.home_planet # Mars

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

IntelligentLife
, наследуются классами
Terran
и
Martian
.

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

Листинг 11.14. Параметрические классы: самое лучшее решение

class IntelligentLife

 class << self

attr_accessor :home_planet

 end

 # ...

end

class Terran < IntelligentLife

 self.home_planet = "Earth"

 #...

end

class Martian < IntelligentLife

 self.home_planet = "Mars"

 #...

end

puts Terran.home_planet # Earth

puts Martian.home_planet # Mars

Здесь мы открываем синглетный класс и определяем метод доступа

home_planet
. В двух подклассах определяются собственные методы доступа и устанавливается переменная. Теперь методы доступа работают строго в своих классах.

В качестве небольшого усовершенствования добавим еще вызов метода

private
в синглетный класс:

private :home_planet=

Сделав метод установки закрытым, мы запретили изменять значение вне иерархии данного класса. Как всегда,

private
реализует «рекомендательную» защиту, которая легко обходится. Но объявление метода закрытым по крайней мере говорит, что мы не хотели, чтобы метод вызывался вне определенного контекста.

Есть и другие способы решения этой задачи. Проявите воображение.

11.2.5. Использование продолжений для реализации генератора

Одно из самых трудных для понимания средств Ruby — продолжение (continuation). Это структурированный способ выполнить нелокальный переход и возврат. В объекте продолжения хранятся адрес возврата и контекст выполнения. В каком-то смысле это аналог функций

setjmp
/
longjmp
в языке С, но объем сохраняемого контекста больше.

Метод

callcc
из модуля
Kernel
принимает блок и возвращает объект класса
Continuation
. Возвращаемый объект передается в блок как параметр, что еще больше все запутывает.

В классе

Continuation
есть всего один метод
call
, который обеспечивает нелокальный возврат в конец блока
callсс
. Выйти из метода
callcc
можно либо достигнув конца блока, либо вызвав метод
call
.

Считайте, что продолжение — что-то вроде операции «сохранить игру» в классических «бродилках». Вы сохраняете игру в точке, где все спокойно, а потом пробуете выполнить нечто потенциально опасное. Если эксперимент заканчивается гибелью, то вы восстанавливаете сохраненное состояние игры и пробуете пойти другим путем.

Самый лучший способ разобраться в продолжениях — посмотреть фильм «Беги, Лола, беги».

Есть несколько хороших примеров того, как пользоваться продолжениями. Самые лучшие предложил Джим Вайрих (Jim Weirich). Ниже показано, как Джим реализовал «генератор» после дискуссии еще с одним программистом на Ruby, Хью Сассе (Hugh Sasse).

Идея генератора навеяна методом

suspend
из языка Icon (он есть также в Prolog), который позволяет возобновить выполнение функции с места, следующего за тем, где она в последний раз вернула значение. Хью называет это «yield наоборот».

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

Сапер. Том IV

Вязовский Алексей
4. Сапер
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Сапер. Том IV

Дорогами алхимии

Видум Инди
2. Под знаком Песца
Фантастика:
альтернативная история
аниме
5.00
рейтинг книги
Дорогами алхимии

Барон нарушает правила

Ренгач Евгений
3. Закон сильного
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Барон нарушает правила

Эволюционер из трущоб. Том 5

Панарин Антон
5. Эволюционер из трущоб
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Эволюционер из трущоб. Том 5

Темные тропы и светлые дела

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

Хозяин Стужи 2

Петров Максим Николаевич
2. Злой Лед
Фантастика:
аниме
фэнтези
попаданцы
5.75
рейтинг книги
Хозяин Стужи 2

Эпоха Опустошителя. Том II

Павлов Вел
2. Вечное Ристалище
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Эпоха Опустошителя. Том II

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

Винокуров Юрий
15. Кодекс Охотника
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга XV

Вернуть невесту. Ловушка для попаданки

Ардова Алиса
1. Вернуть невесту
Любовные романы:
любовно-фантастические романы
8.49
рейтинг книги
Вернуть невесту. Ловушка для попаданки

Полигон

Гостева Ирина
S.T.A.L.K.E.R.
Фантастика:
боевая фантастика
7.78
рейтинг книги
Полигон

Законы Рода. Том 4

Мельник Андрей
4. Граф Берестьев
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 4

Князь Целитель 6

Ткачев Андрей Юрьевич
6. Князь Целитель
Фантастика:
боевая фантастика
городское фэнтези
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Князь Целитель 6

Эволюционер из трущоб. Том 3

Панарин Антон
3. Эволюционер из трущоб
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
6.00
рейтинг книги
Эволюционер из трущоб. Том 3

На границе империй. Том 7. Часть 4

INDIGO
Вселенная EVE Online
Фантастика:
боевая фантастика
космическая фантастика
5.00
рейтинг книги
На границе империй. Том 7. Часть 4