Программирование на языке Ruby, часть 1

Автор: Hiran Ramankutty

Перевод:Андрей Киселев


Введение

Ruby представляет собой объектно-ориентированный язык программирования интерпретирующего типа. Он был создан программистом из Японии -- Юкихиро Матсумото (Yukihiro Matsumoto), где этот язык пользуется большей популярностью нежели Python или Perl! Первая часть из серии является введением в основы языка Ruby. Более глубокий материал будет даваться в последующих частях.

Я не собираюсь превозносить язык Ruby и доказывать его преимущества перед другими языками программирования. Большинство из нас прекрасно понимают, что каждый язык программирования имеет свои неповторимые черты. И ваш выбор скорее будет зависеть от ваших личных предпочтений и доступности стандартных библиотек, нежели от неких таинственных технических проблем.

Требования

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

Hello World

Начнем с обычной в таких случаях программы `Hello, World'

% cat > hello.rb
print "Hello World\n"
^D
% ruby hello.rb
Hello World
%

Переменные

Имена переменных должны начинаться с символа:

                $                       глобальная переменная
                @                       переменная экземпляра (поле объекта, данные-член)
                a-z или '_'             локальная переменная
                A-Z                     константа

Кроме того существуют еще две псевдопеременные, которые являются исключением из вышеуказанного правила - это `self' и `nil'.

Обе они именуются как локальные переменные, но таковыми не являются! Реальный смысл этих переменных станет вам понятен немного позже.

Глобальные переменные

Имена глобальных переменных должны начинаться с символа `$'. Глобальные переменные доступны из любой части программы. Следует отметить, что неинициализированная глобальная переменная имеет значение 'nil'. Этот факт демонстрирует следующий пример:

 % ruby
 print $foo,"\n"
 $foo = 5
 print $foo,"\n"
 ^D
 %

Результат работы интерпретатора:
nil
5

Эта особенность дает возможность `связывать' процедуры с глобальными переменными, т.е. при изменении значения переменной `связанная' процедура будет вызываться автоматически. Но об этом позже!

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

Локальные переменные

Имена локальных переменных должны начинаться с прописных (маленьких) символов латинского алфавита или с символа '_'. В отличие от глобальных переменных и ссылок на переменные, локальные переменные не принимают значение 'nil', например, при выполнении следующего кода:

% ruby
print foo
^D

Вы получите сообщение об ошибке:
      "undefined local variable or method 'foo' for #(object...)".

Область видимости локальных переменных ограничивается одной из следующих разновидностей блоков программы

Локальная переменная, инициализированная в каком либо блоке (или процедуре), после выхода за пределы блока становится неопределенной. Например:
def foo(n)
        k = 2 * n
        print "\n",k,"\n"
        print defined? k,"\n"
end

foo 3
print defined? k,"\n"
^D

Вывод интерпретатора:
  

6
local-variable
nil

В этом примере оператор `defined?' используется для проверки существования передаваемого ему аргумента. Результаты работы оператора "local-variable" и "nil" понятны и так и в комментариях не нуждаются.

Константы

Имена констант начинаются с заглавных (больших) символов латинского алфавита. Но, как правило, программирующие на Ruby, дают константам имена, состоящие только из заглавных символов. Так, например и 'Foo', и 'FOO' являются константами. Как и в случае с локальными переменными, константы инициализируются оператором присваивания, а обращение к неинициализированной константе, равно как и попытка изменения инициализированной константы, вызывает сообщение об ошибке. Проверьте это самостоятельно.

Строки

Строки в Ruby ограничиваются либо одинарными ('...'), либо двойными кавычками ("..."). Однако такие строки имеют различия между собой. При использовании двойных кавычек допускается вставлять в строки управляющие escape-последовательности, начинающиеся с символа '\', а также вычислять выражения с помощью конструкции #{}. Например:

print "\n"
print '\n'
print "\001","\n"
print '\001',"\n"
print "abcd #{5*3} efg","\n"
var = " abc "
print "1234#{var}567","\n"
^D

\n
\001
abcd 15 efg
1234abc567

Дополнительную информацию по строкам вы получите в разделе, посвященном массивам, поскольку массивы и строки во многом похожи друг на друга.

Массивы

Для определения массивов используются квадратные скобки '[]'. Массивы в Ruby являются гетерогенными (т.е. могут содержать данные различных типов).

a = [1,2,"3"]
print a,"\n"
^D

123

Однако, если вы попытаетесь заставить интерпретатор подсчитать сумму элементов массива, показанного выше, то он выдаст сообщение об ошибке:

         Error!!String cannot be coerced into Fixnum
Дело в том, что элемент массива `3' хранится в виде строки. Если вычисление суммы элементов массива задать следующим образом:
a = [1,2,"3"]
b = a[0] + a[1] + a[2].to_i
print b,"\n"
^D

6
То интерпретатор выполнит его без ошибки. Добавление '.to_i' к 3-му элементу массива (т.е. a[2].to_i) заставляет интерпретатор выполнить преобразование содержимого элемента массива a[2] в целое со знаком. Ради эксперимента можете попробовать подставить '.to_s'.

К массивам можно применять операции конкатенации (слияния) и повторения.

a = [1,2,"3"]
print a + ["foo","bar"]
print a * 2
^D

Результат
123foobar
123123

Можно получить "срез" массива:

a = [1,2,"3","foo","bar"]
print a[0],"\n"
print a[0,2],"\n"
print a[0..3],"\n"
print a[-2..2],"\n"
print a[-3..-1],"\n"

Массивы и строки взаимно конвертируемы. Массив можно преобразовать в строку с помощью метода 'join', а строку -- в массив с помощью метода 'split'.

a = [1,2,3]
print a[2],"\n"
a = a.join(":")
print a[2],"\n"
print a,"\n"
a = a.split(":")
print a[2],"\n"
print a,"\n"
^D

Ассоциативные массивы (хэши (англ. hash) или словари)-- еще один немаловажный вид представления данных. Хэши содержат пары ``ключ'' и ``значение'', см. пример ниже:

h = {1 => 2, "2" => "4"}
print hash,"\n"
print hash[1],"\n"
print hash["2"],"\n"
print hash[5],"\n"
^D

Я, надеюсь, результаты убедительны!

Управляющие конструкции

If - else

Попробуем написать функцию вычисления факториала. Математическое определение факториала:

      n! = 1                    (если n==0)
      n! = n * (n-1)!           (иначе)
      
На Ruby вычисление факториала может быть реализовано следующим образом:
def fact(n)
        if n == 0
                1
        else
                n * fact(n-1)
        end
end
print fact 4,"\n"

В результате получится 24.

Из-за наличия ключевого слова `end' Ruby иногда называют 'Алголо-подобным' языком. В данном примере рекурсивной функции вы можете заметить отсутствие оператора возврата результата (return). Естественно, использование этого оператора не возбраняется, но в данной ситуации он является излишним, поскольку в качестве возвращаемого значения принимается результат вычисления последнего выражения.

Цикл for

for i in 0..4
        body-of-for
end

Где i -- переменная цикла, а 0..4 -- диапазон значений. Для строковых переменных, заголовок цикла for можно записать так:

for i in "abc"

Цикл while

Попробуйте запустить этот пример

i=0
while i < 10
        print i+=1,"\n"
end

Case

Оператор выбора case используется для проверки набора условий. В результате работы следующего примера

i = 7
case i
when 2..5
        print "i in 2 to 5\n"
when 6..10
        print "i in 6 to 10\n"
end
^D

вы получите

i in 6 to 10

2..5 -- означает диапазон значений от 2 до 5 включительно. Здесь проверяется - попадает ли значение переменной i в заданный диапазон.

В случае строк, оператор case будет выглядеть примерно так:

case 'abcdef'
when 'aaa','bbb'
        print 'contains aaa or bbb \n"
when /def/
        print "contains def \n"
end
^D
contains def

Обратите внимание на слэши (символ "/"), которые окружают ключевое слово "def". Они используются для задания границ регулярного выражения, которые мы рассмотрим позднее.

Дополнительные управляющие конструкции

Оператор case, из примера, приведенного выше, проверяет попадание значения переменной i в диапазон 2..5. Эта же проверка может быть записана несколько иначе, например:

(2..5) === i

Оператор отношения '===' используется для проверки выполнения нескольких условий одновременно и интерпретируется подобно ключевому слову when.

Попробуйте самостоятельно реализовать функцию, подобную isalnum(),isalpha(),isnum() и т.п. с помощью оператора '===' внутри конструкции if.

При использовании конструкций if и while для проверки отдельных значений, код может быть несколько сокращен

i = 7
print "contained in 5..10\n" if (5..10) === i
print i-=1,"\n" while i > 0
^D
contained in 5..10
6
5
4
3
2
1
0

Иногда может возникнуть необходимость в инвертировании проверяемого условия. Так, условие "если" (if) при инвертировании приобретает смысл "если не", условие while -- в условие until и т.д.

Существует четыре различных варианта управления исполнением цикла. Первый, аналогичный C -- break, означает выход за тело цикла. Второй -- next, переход в начало следующей итерации (аналог continue в C). Третий -- redo, перезапускает текущую итерацию. Следующий C-код иллюстрирует механизм работы этих трех методов (break, next и redo):

while(condition) {
  label_redo:
        goto label_next;                /* ruby's "next" */
        goto label_break;               /* ruby's "break"*/
        goto label_redo;                /* ruby's "redo" */
        ...
        ...
  label_next:
}
label_break:
...

И четвертый вариант -- оператор return. Фактически, этот оператор приводит не только к прерыванию цикла, но и к завершению работы метода (функции), который содержит прерываемый цикл.

Заключение

Мы рассмотрели некоторые элементарные особенности языка программирования Ruby в том объеме, который позволит вам написать свои первые программы. В своих следующих статьях, посвященных этому "драгоценному камню" (слово Ruby может быть переведено на русский язык как "рубин", прим. перев.), я буду делиться своим опытом , приобретенным при его изучении. До свидания!

Hiran Ramankutty

Я -- студент последнего курса Правительственного Колледжа Компьютерных Наук в городе Трикур (Trichur). Кроме Linux, я с большим удовольствием занимаюсь изучением физики.
Copyright (C) 2002, Hiran Ramankutty.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 81 of Linux Gazette, August 2002

Вернуться на главную страницу