Программисты пишут на Ruby

advertisement
Некоммерческая организация «Ассоциация московских вузов»
Государственное образовательное учреждение
высшего профессионального образования
Московский государственный индустриальный университет
ГОУ ВПО МГИУ
Научно-образовательный материал
«Программисты пишут на Ruby»
Состав научно-образовательного коллектива:
Курасов Ю.В., ведущий инженер
Виноградова Л.А., ведущий инженер
Москва 2010 г.
Программисты пишут на Ruby
Начнем с примеров, показывающих, что знание библиотек ввода/вывода
языков C и C++ пригодится и в Ruby.
printf "Число: %5.2f; Строка: %s", 1.23, "Привет!"
endl = "\n"; $stdout << 17 << " красных шариков" <<
endl
line = gets; print line
Специальная
глобальная
переменная
$_ всегда содержит результат
последней операции чтения. Она же используется как аргумент по
умолчанию во многих конструкциях. Следующая программа, например,
печатает все строки из входного потока, которые содержат слово Ruby.
while gets
# присваивание очередной строки
переменной $_
if /Ruby/
print
# сопоставление ее с образцом Ruby
# печать $_
end
end
Ruby-стиль, однако, рекомендует использовать итератор each:
ARGF.each { |line|
print line
if line =~ /Ruby/ }
ARGF в Ruby -- это объект, который представляет собой конкатенацию
содержимого всех файлов, имена которых заданы в командной строке, либо
просто стандартный поток ввода (в случае отсутствия аргументов).
Вот как выглядит на Ruby программа вычисления факториала числа,
указываемого в качестве аргумента командной строки:
def fact(n)
return 1 if n == 0
f = 1
while n>0
f *= n
n -= 1
end
return f
end
print fact(ARGV[0].to_i), "\n"
Для вычисления с помощью этой программы, размещенной в файле
fact.rb, значения 100! достаточно выполнить команду ruby fact.rb
100.
Три
программы,
приведенные
рекурсивно
ниже,
вычисляющие
позволяют
интерпретаторов Ruby, Python и Perl.
# Ruby
def fib(n)
if n<2
n
else
fib(n-2)+fib(n-1)
end
end
print fib(30), "\n"
# Python
def fib(n):
if n<2:
return n
30-е
сравнить
число
Фибоначчи,
производительность
else:
return fib(n-2)+fib(n-1)
print fib(30)
# Perl
sub fib {
my($n)=@_;
if ($n<2) {
return $n;
}
else {
return fib($n-2)+fib($n-1);
}
}
print fib(30), "\n";
Еще одна классическая задача -- определение с помощью решета Эратосфена
списка всех простых чисел, не превосходящих заданного (100 по
умолчанию).
max = Integer(ARGV.shift || 100)
sieve = []
for i in 2 .. max
sieve[i] = i
end
for i in 2 .. Math.sqrt(max)
next unless sieve[i]
(i*i).step(max, i) do |j|
sieve[j] = nil
end
end
puts sieve.compact.join ", "
В качестве следующего примера рассмотрим решение на языке Ruby задачи,
которая часто предлагается студентам первого курса, изучающим языки
C/C++: для заданного текстового файла определить число вхождений в него
каждого из встречающихся в нем слов. Использование ассоциативных
массивов и ряда стандартных методов работы с файлами и строками
позволяет написать чрезвычайно краткую и ясную программу.
freq = Hash.new(0)
while gets()
for word in $_.split(/\W+/)
freq[word] += 1
end
end
for word in freq.keys.sort!
print word, " -- ", freq[word], "\n"
end
Приведем два простых примера использования стандартной библиотеки
классов. В результате выполнения первой программы будет найдено, что
7/8+1/8=1, а 7/8*1/8=7/64; вторая из них вычислит (1 + i)64.
require "rational"
a = Rational(7,8)
b = Rational(1,8)
print a, "+", b, "=", a+b, "; ", a, "*", b, "=", a*b,
"\n"
require "complex"
a = Complex(1,1);
print a**64
Без подробных объяснений приведем две эквивалентные программы,
иллюстрирующие переопределение оператора [] для класса SongList.
Ассоциативный массив (associative array, hash или dictionary) допускает
индексирование произвольными объектами, а не только целыми числами. В
данном случае оператор [] позволяет находить нужную песню не только по
номеру, но и по ее названию.
class SongList
def [](key)
if key.kind_of?(Integer)
return @songs[key]
else
for i in 0...@songs.length
return @songs[i] if key == @songs[i].name
end
end
return nil
end
end
class SongList
def [](key)
return @songs[key] if key.kind_of?(Integer)
return @songs.find { |aSong| aSong.name == key }
end
end
Так как Ruby унаследовал лучшие особенности многих языков, то для
выполнения достаточно стандартных действий обычно имеется несколько
разных возможностей. Вот 13 (!) различных способов напечатать числа от 0
до 9:
i = 0
i = 0
while i < 10
begin
print i , ' '
print i , ' '
i += 1
i += 1
end
end while i < 10
i = 0
i = 0
until i >= 10
begin
print i , ' '
print i, ' '
i += 1
i += 1
end
end until i >= 10
for i in [0,1,2,3,4,5,6,7,8,9]
for i in (0..9)
print i, ' '
print i, ' '
end
end
for i in (0...10)
10.times do |i|
print i, ' '
print i, ' '
end
end
0.upto(9) do |i|
9.downto(0) do |i|
print i, ' '
print i, ' '
end
end
(0..9).each do |i|
(0...10).each do |i|
print i, ' '
end
i = 0
loop do
print i, ' '
end
if i < 10 then print i, ' ' else break
end
i += 1
end
В заключение вопрос для тех, кто не знает языка Ruby: что напечатает
следующая программа?
print ["L", "R", "H", "T"].collect { |x| x.succ }
Если вы сумеете угадать ответ, то это будет лучшим подтверждением тому
факту, что Ruby интуитивно ясный язык. Если же не угадаете, то у вас будет
еще одна причина изучить его.
Download