Программирование на языке Ruby
Программирование на языке Ruby читать книгу онлайн
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
В листинге 11.15 представлена предложенная Джимом реализация генератора чисел Фибоначчи. Продолжения применяются для того, чтобы сохранить состояние между вызовами.
class Generator
def initialize
do_generation
end
def next
callcc do |here|
@main_context = here;
@generator_context.call
end
end
private
def do_generation
callcc do |context|
@generator_context = context;
return
end
generating_loop
end
def generate(value)
callcc do |context|
@generator_context = context;
@main_context.call(value)
end
end
end
# Порождаем подкласс и определяем метод generating_loop.
class FibGenerator < Generator
def generating_loop
generate(1)
a, b = 1, 1
loop do
generate(b)
a, b = b, a+b
end
end
end
# Создаем объект этого класса...
fib = FibGenerator.new
puts fib.next # 1
puts fib.next # 1
puts fib.next # 2
puts fib.next # 3
puts fib.next # 5
puts fib.next # 8
puts fib.next # 13
# И так далее...
Есть, конечно, и более практичные применения продолжений. Один из примеров — каркас
Borges
Seaside
Проблема в том, что продолжение — «дорогая» операция. Необходимо сохранить состояние и потратить заметное время на переключение контекста. Если производительность для вас критична, прибегайте к продолжениям с осторожностью.
11.2.6. Хранение кода в виде объекта
Неудивительно, что Ruby предлагает несколько вариантов хранения фрагмента кода в виде объекта. В этом разделе мы рассмотрим объекты
Proc
Method
UnboundMethod
Встроенный класс
Proc
Proc
myproc = Proc.new { |a| puts "Параметр равен #{а}" }
myproc.call(99) # Параметр равен 99
Кроме того, Ruby автоматически создает объект Proc, когда метод, последний параметр которого помечен амперсандом, вызывается с блоком в качестве параметра:
def take_block(x, &block)
puts block.class
x.times {|i| block[i, i*i] }
end
take_block(3) { |n,s| puts "#{n} в квадрате равно #{s}" }
В этом примере демонстрируется также применение квадратных скобок как синонима метода
call
Proc
0 в квадрате 0
1 в квадрате 1
2 в квадрате 4
Объект
Proc
&
myproc = proc { |n| print n, "... " }
(1..3).each(&myproc) # 1... 2... 3...
Ruby позволяет также превратить метод в объект. Исторически для этого применяется метод
Object#method
Method
str = "cat"
meth = str.method(:length)
a = meth.call # 3 (длина "cat")
str << "erpillar"
b = meth.call # 11 (длина "caterpillar")
str = "dog"
# Обратите внимание на следующий вызов! Переменная str теперь ссылается
# на новый объект ("dog"), но meth по-прежнему связан со старым объектом.
с = meth.call # 11 (длина "caterpillar")
Начиная с версии Ruby 1.6.2, можно также применять метод
Module#instance_method
UnboundMethod
UnboundMethod
Method