Хэл Фултон - Программирование на языке Ruby стр 10.

Шрифт
Фон

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

Предложение case выбирает одну из трех ветвей: пользователь указал С, F или какое-то другое значение в качестве шкалы. В первых двух случаях выполняется вычисление, в третьем мы печатаем сообщение об ошибке и выходим.

Кстати, предложение case в Ruby позволяет гораздо больше, чем показано в примере. Нет никаких ограничений на типы данных, а все выражения могут быть произвольно сложными, в том числе диапазонами или регулярными выражениями.

В самом вычислении нет ничего интересного. Но обратите внимание, что переменные с и f впервые встречаются внутри ветвей case. В Ruby нет никаких объявлений - переменная начинает существовать только в результате присваивания. А это означает, что после выхода из case лишь одна из переменных elif будет иметь действительное значение.

Мы воспользовались этим фактом, чтобы понять, какая ветвь исполнялась, и в зависимости от этого вывести то или другое сообщение. Сравнение f с nil позволяет узнать, есть ли у переменной осмысленное значение. Этот прием применен только для демонстрации возможности: ясно, что при желании можно было бы поместить печать прямо внутрь предложения case.

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

1.2.6. Циклы и ветвление

Потратим немного времени на изучение управляющих конструкций. Мы уже видели простое предложение if и модификатор if. Существуют также парные структуры, в которых используется ключевое слово unless (в них также может присутствовать необязательная ветвь else), а равно применяемые в выражениях формы if и unless. Все они сведены в таблицу 1.1.

Таблица 1.1. Условные предложения

Формы с ifФормы с unless
if x < 5 then statement1 endunless x >= 5 then statement1 end
if x < 5 then statement1 else statement2 endunless x < 5 then statement2 else statement1 end
statement1 if y == 3statement1 unless y != 3
x = if a>0 then b else c endx = unless a<=0 then с else b end

Здесь формы с ключевыми словами if и unless, расположенные в одной строке, выполняют в точности одинаковые функции. Обратите внимание, что слово then можно опускать во всех случаях, кроме последнего (предназначенного для использования в выражениях). Также заметьте, что в модификаторах (третья строка) ветви else быть не может.

Предложение case в Ruby позволяет больше, чем в других языках. В его ветвях можно проверять различные условия, а не только сравнивать на равенство. Так, например, разрешено сопоставление с регулярным выражением. Проверки в предложении case эквивалентны оператору ветвящегося равенства (===), поведение которого зависит от объекта. Рассмотрим пример:

case "Это строка символов."

when "одно значение"

puts "Ветвь 1"

when "другое значение"

puts "Ветвь 2"

when /симв/

puts "Ветвь 3"

else

puts "Ветвь 4"

end

Этот код напечатает Ветвь 3. Почему? Сначала проверяемое выражение сравнивается на равенство с двумя строками: "одно значение" и "другое значение". Эта проверка завершается неудачно, поэтому мы переходим к третьей ветви. Там находится образец, с которым сопоставляется выражение. Поскольку оно соответствует образцу, то выполняется предложение print. В ветви else обрабатывается случай, когда ни одна из предшествующих проверок не прошла.

Если проверяемое выражение - целое число, то его можно сравнивать с целочисленным диапазоном (например, 3..8); тогда проверяется, что число попадает в диапазон. В любом случае выполняется код в первой подошедшей ветви.

В Ruby имеется богатый набор циклических конструкций. К примеру, while и until - циклы с предварительной проверкой условия, и оба работают привычным образом: в первом случае задается условие продолжения цикла, а во втором - условие завершения. Есть также их формы с модификатором, как для предложений if и unless. Кроме того, в модуле Kernel есть метод loop (по умолчанию бесконечный цикл), а в некоторых классах реализованы итераторы.

В примерах из таблицы 1.2 предполагается, что где-то определен такой массив list:

list = %w[alpha bravo charlie delta echo];

В цикле этот массив обходится и печатается каждый его элемент.

Таблица 1.2. Циклы

# Цикл 1 (while)# Цикл 2 (until)
i=0 while i < list.size do print "#{list[i]} " i += 1 endi=0 until i == list.size do print "#{list[i]} " i += 1 end
# Цикл 3 (for)# Цикл 4 (итератор 'each')
for x in list do print "#{x} " endlist.each do |x| print "#{x} " end
# Цикл 5 (метод 'loop')# Цикл 6 (метод 'loop')
i = 0 n=list.size-1 loop do print "#{list[i]} " i += 1 break if i > n endi=0 n=list.size-1 loop do print "#{list[i]} " i += 1 break unless i <= n end
# Цикл 7 (итератор 'times')# Цикл 8 (итератор 'upto')
n=list.size n.times do |i| print "#{list[i]} " endn=list.size-1 0.upto(n) do |i| print "#{list[i]} " end
# Цикл 9 (for)# Цикл 10 ('each_index')
n=list.size-1 for i in 0..n do print "#{list[i]} " endlist.each_index do |x| print "#{list[x]} " end

Рассмотрим эти примеры более подробно. Циклы 1 и 2 - "стандартные" формы циклов while и until; ведут они себя практически одинаково, только условия противоположны. Циклы 3 и 4 - варианты предыдущих с проверкой условия в конце, а не в начале итерации. Отметим, что использование слов begin и end в этом контексте - просто грязный трюк; на самом деле это был бы блок begin/end (применяемый для обработки исключений), за которым следует модификатор while или until. Однако для тех, кто желает написать цикл с проверкой в конце, разницы нет.

На мой взгляд, конструкции 3 и 4 - самый "правильный" способ кодирования циклов. Они заметно проще всех остальных: нет ни явной инициализации, ни явной проверки или инкремента. Это возможно потому, что массив "знает" свой размер, а стандартный итератор each (цикл 6) обрабатывает такие детали автоматически. На самом деле в цикле 5 производится неявное обращение к этому итератору, поскольку цикл for работает с любым объектом, для которого определен итератор each. Цикл for - лишь сокращенная запись для вызова each; часто такие сокращения называют "синтаксической глазурью", имея в виду, что это не более чем удобная альтернативная форма другой синтаксической конструкции.

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

В циклах 7 и 8 используется тот факт, что у массива есть числовой индекс. Итератор times исполняется заданное число раз, а итератор upto увеличивает свой параметр до заданного значения. И тот, и другой для данной ситуации приспособлены плохо.

Ваша оценка очень важна

0
Шрифт
Фон

Помогите Вашим друзьям узнать о библиотеке