Файлы
Справка
Телеграм чат начинающих программистов. Общаемся и помогаем друг другу
Если ссылка не открывается, можно найти нас в поиске по чатам @rubyrush
или
пойти другим путем
В этом уроке у нас очень важная тема: методы.
Мы узнаем как писать свои маленькие подпрограммы — методы.
Что нужно знать перед тем, как писать свой метод, когда их стоит использовать,
а когда нет. И зачем в Ruby нужны ключевые слова def
и return
, а также попутно узнаем про оператор %
и метод is_a?
.
return
Если вкратце, то методы нужны для описания повторяющихся действий.
Представьте, что вам в подробностях необходимо описать ваш день, скорее всего, вы будете использовать фразы:
На самом деле, за каждым из этих слов стоит масса действий, которые каждый человек делает по-разному. Но удобнее всего описывать ваш день простыми словами, потому что по большому счету не так важно, чем именно вы завтракаете и как долго вы чистите зубы во время умывания.
Такие рутинные действия, которые спрятаны за короткое имя, в программах называются функции или методы. И сейчас мы расскажем вам о том, как ими пользоваться в Ruby.
Внимание, откровение! Каждый раз, когда мы во всех наших программах выводили что-то на экран с помощью команды puts
, мы использовали метод puts
!
puts 'Я строка!'
Мы совершенно не представляем, как именно Ruby выводит строку на экран, мы просто пользуемся этим методом, зная его имя (puts) и получаем от него ожидаемый результат. В этом вся сила методов!
Так как единственное, что нам нужно знать про метод, чтобы его вызвать, это его имя, то существует опасность назвать какую-нибудь переменную также, как и какой-то метод программы.
Вам следует всегда помнить о том, что вы не можете называть свои переменные также, как и методы (а также у разных переменных не может быть одинаковых имён, программа просто не поймёт, что это разные переменные). Всегда называйте свои переменные аккуратно — так, чтобы у разных переменных были разные имена, и они не пересекались с именами известных вам методов.
Когда вы идёте в магазин или, говоря нашей новой терминологией, выполняете метод «сходить в магазин» — у вас с собой обычно есть список всего, что вам нужно купить. Метод всегда один и тот же, а список всегда разный (ну или почти всегда).
Так и в программировании, один метод может выполнять разные действия. Например метод sleep
всегда приостанавливает выполнение программы, но он может подвесить выполнение программы как на 1, так и на 10 секунд, в зависимости от того числа, которое вы напишете после его вызова:
sleep 1
sleep 10
Опять же, нам совершенно не важно, как именно будет выполняться задержка, важно лишь сколько секунд она будет длится.
Мы передаём методу эту важную информацию в виде параметров. Параметры — это информация, которую мы передаём в метод, чтобы управлять поведением метода.
Обычно параметры передаются в скобках после названия метода:
puts("Я параметр команды puts")
Но в Ruby скобки при передаче параметров методам можно не писать и это очень удобно, чем мы и пользуемся постоянно:
puts "Я другой параметр команды puts"
Метод puts
, кстати, можно вызвать и без параметров, тогда он выведет на экран пустую строчку с символом переноса строки \n
.
Если параметров несколько, они передаются через запятую
array.push "Я первый параметр", "Я - второй"
Как мы помним из урока про массивы, это добавит в массив array
два строковых элемента.
У объектов тоже бывают методы. Подробнее о том, как это всё устроено, мы будем рассказывать в уроке про классы. А пока расскажем, как ими пользоваться.
Чтобы использовать метод объекта, нужно написать имя объекта (переменную, которая на него указывает), потом точку, а потом — имя метода, который мы хотим вызвать.
Так происходит практически во всех языках, Ruby не исключение.
fruits = ['orange', 'mango', 'apple']
puts fruits.to_s
Здесь мы выводим на экран массив fruits
, преобразованный в строку.
Мы вызвали метод to_s
объекта fruits
, класс которого Array
(массив). Дело в том, что у всех объектов класса Array
есть такой метод to_s
, который преобразует объект в строку. Подробнее об этом ещё будем говорить в уроках про классы.
Полезный метод, который в Ruby есть у любого объекта, называется methods
. Это метод, который возвращает список всех методов объекта. Другое дело, это не всегда помогает, так что учитесь гуглить.
Если набрать в google
ruby Array methods
То вы без труда найдёте ссылку на страницу со всем списком методов массивов в Ruby и подробным описанием и примерами к каждому методу.
В большинстве языков каждый метод обычно что-то возвращает. В том числе и в Ruby все методы на самом деле хоть что-нибудь, да оставляют после себя. То есть, если написать
a = method
То в переменной a
будет содержаться результат работы метода method
. Наш любимый puts
, к слову, всегда возвращает пустой объект nil
.
a = puts "Я puts, я не хочу ничего возвращать, я хочу просто печатать"
После этого в переменной a
будет nil
. nil
это специальное ключевое слово, которое означает в Ruby «пустой объект», ничего, пустоту, ничто! Это очень важная штука, вы часто с ней будете встречаться.
Возвращаемое значение это как сдача, которую вам дают в магазине: вы передаете определенную сумму денег за товар (это параметр метода), кассир берет деньги и пробивает вам товар, а затем возвращает вам сдачу. Если вы дали денег под расчет, то сдачи не будет (метод «кассир» вернет вам nil
) :).
Давайте возьмём пример посложнее. Метод now
класса Time
, встроенного в Ruby, возвращает текущее время в специальном формате, если мы запишем его в переменную, а потом выведем его на экран, то у нас получатся простенькие часы, которые показывают время и выключаются.
time = Time.now
puts time
Выведет текущее время:
2014-06-08 11:30:44 +0400
Какие вообще бывают методы, и какие у конкретного метода бывают параметры и возвращаемые значения принято узнавать из документации (Ruby или какой-то библиотеки классов, которую вы используете). Пока же просто повторяйте за нами, из урока в урок мы будем пользоваться новыми методами и объяснять вам их смысл.
Чтобы сделать свою программу понятнее, проще и лучше — нужно писать свои методы. И прятать в них те действия, которые повторяются, которые уместно выделить в отдельную инструкцию. Сейчас разберем подробнее.
Перед тем, как писать свой метод вам необходимо определиться с тремя вещами:
Напишем наш первый метод. Он будет называться say_hi
, он будет на вход получать один параметр name
и ничего не будет возвращать, он просто будет выводить на экран приветствие для указанного имени:
def say_hi(name)
puts "Привет, #{name}"
end
Остановимся немного на синтаксисе.
Во-первых, для объявления метода, чтобы Ruby понял, что мы хотим создать новый метод, нужно написать инструкцию def
.
Во-вторых, после def
нужно указать название нашего нового метода.
В-третьих, после имени метода в скобках нужно указать параметры, если они нужны для работы метода.
И, наконец, в-четвёртых, нужно написать тело метода (аналогично тому, как мы писали тела ветвлений if
и тела циклов while
) в виде набора инструкций до ключевого слова end
, которое будет говорить Ruby, что описание метода закончилось.
В нашем новом методе тело состоит из одной строчки, которая использует параметр name
. Обратите внимание, что параметр метода в теле метода используется как переменная, её не надо объявлять отдельно.
Само объявление метода, как вы догадались, ничего не делает. Мы просто говорим программе: «запомни, say_hi
означает вот что ...». Теперь для того, чтобы что-то произошло, наш метод нужно вызвать, передав ему нужные параметры.
Если после объявления метода написать:
say_hi "Миша"
То при выполнении программы на экран выведется
Привет, Миша
Чтобы использовать методы их нужно сперва объявить (то есть описать с помощью оператора def
имя метода, список параметров и тело метода), а затем использовать в своей программе.
Если вкратце, то когда вы видите, что вы, подобно попугаю, повторяете один и тот же текст в своей программе несколько раз.
В нашем примере про дорогу мы заставляли водителя Ruby через каждую секунду выкрикивать какую-то фразу:
puts "Поехали"
sleep 1
puts "Первый километр"
sleep 1
puts "Второй километр"
sleep 1
puts "Третий километр"
sleep 1
puts "Приехали!"
gets
Обратите внимание, что некоторые действия повторяются. Это верный признак, что можно написать метод, который сократит нашу программу:
def shout_and_wait message
puts message
sleep 1
end
Тогда наш код бы сократился и стал бы вот таким:
shout_and_wait "Поехали"
shout_and_wait "Первый километр"
shout_and_wait "Второй километр"
shout_and_wait "Третий километр"
puts "Приехали!"
gets
Мы добавили метод, но сама программа стала короче и понятнее. В реальных программах использование методов ещё сильнее сокращает код ваших программ.
Чем меньше код программы, тем проще и понятнее он для вас и других программистов, тем проще его поддерживать, не занимаясь «copy + paste».
Короче, методы — это здорово. Вы скоро сами это поймёте. Пока мы только затронули самые азы.
Наш метод shout_and_wait
ничего не возвращает. Он просто выводит строку и усыпляет интерпретатор Ruby на 1 секунду.
Давайте напишем другой метод, который что-нибудь возвращает.
Вот простенький метод суммирования двух чисел
def sum a, b
return a + b
end
Он состоит из названия (sum
), двух параметров (a
и b
) и тела, которое возвращает сумму входных параметров с помощью специального ключевого слова return
. Теперь давайте его вызовем, как обычно, мы пишем название метода, параметры, но на этот раз, мы запишем результат работы метода в отдельную переменную. Именно туда попадёт то, что вернёт метод своим return
.
number = sum(35, 24)
puts number
Выведет в консоль
59
Итак, оператор return
заканчивает выполнение метода и возвращает значение, которое стоит после этого оператора (это может быть значение какой-то переменной, выражения или даже результат работы другого метода).
Имейте в виду, что после вызова return
метод прекращает работу, программа покидает тело метода и возвращается к работе в то место, откуда мы метод вызвали.
Азы освоены и давайте напишем что-нибудь действительно полезное и нужное. Очень часто на сайтах или в программах у нас есть необходимость сообщить пользователю, что у него в программе есть какое-то количество каких-то объектов: 2 рубл_я_, 1 комментар_ий_, 15 сообщен_ий_, 38 попуга_ев_ и т.д.
Обратите внимание, что в зависимости от числа, склонение существительного будет другим.
Наш замечательный русский язык велик, могуч и сложен. Вот у англичан такой проблемы нет, если один, то 1 book, если больше одного, то 2 books или 1000 books и т. д.
Если разобраться, то выяснится, что в русском языке словоформы всего 3. Одна используется для единственного числа: «1 попуг_ай_». Другая используется для небольшого количества предметов: «2, 3 или 4 попуг_ая_». И, наконец, последняя форма используется, когда объектов много: «5 или больше попуг_аев_».
Итак, постановка задачи: «Написать программу, которая в качестве параметров берёт произвольное число и три словоформы и возвращает ту форму слова, которой соответствует число».
Как обычно определимся с тремя вещами про метод:
sklonenie
number
и три строки-словоформы krokodil, krokodila и krokodilov
Для наглядности назовем наши параметры krokodil
, krokodila
, krokodilov
— при вызове метода в качестве первого параметра нужно передать единственное число (например, один «крокодил»), в качестве второго — форму для нескольких объектов (скажем, три «крокодила»), и третий параметр – форма для большого числа объектов (допустим, пятьсот «крокодилов»).
Всё, можно приступать к написанию.
Как обычно, мы создадим папку lesson9
в нашей рабочей папке c:\rubytut
, и в ней создадим файл sklonenie.rb
.
def sklonenie(number, krokodil, krokodila, krokodilov)
# тут будет тело метода
end
Обратите внимание, что в словосочетаниях 1 крокодил, 21 крокодил и 101 крокодил разницы в словоформе нет, то же самое верно для «35 крокодилов» или «42 попугая».
Важна последняя цифра, то есть, остаток от деления исходного числа на 10 (надеюсь, вы помните, что такое остаток от деления целых чисел <ссылку на вики>).
В программировании остаток от деления одного числа на другое вычисляется с помощью оператора процент (%).
puts 37%10
Выведет в консоль 7, потому что если 37 поделить на десять — будет 3.7. То есть десятка входит в число 37 целых три раза и остается еще хвостик — семерка. Этот хвостик и есть остаток от деления.
В нашем методе мы воспользуемся этим оператором, чтобы записать в переменную ostatok
последнюю цифру или остаток от деления на 10 указанного при вызове метода числа (которое, напомню, у нас лежит в параметре-переменной number
).
ostatok = number % 10
Например, если кто-то напишет
sklonenie 35, 'рубль', 'рубля', 'рублей'
То в переменной `ostatok будет лежать число 5.
Дальше всё просто, если остаток равен единице, то используем первую словоформу, если остаток от 2 до 4 (включительно), то используем вторую словоформу и, наконец, если остаток от 5 до 9 (или 0), то используем третью словоформу.
if (ostatok == 1)
return krokodil
end
if (ostatok >= 2 && ostatok <= 4)
return krokodila
end
if (ostatok >= 5 && ostatok <= 9 || ostatok == 0)
return krokodilov
end
Наконец, напишем вызов нашего метода. Используем сюжет из знаменитого детектива Агаты Кристи «Десять негритят» (рекомендуем также посмотреть отличный фильм по этой книге).
puts "#{skolko} #{sklonenie(skolko, "негритёнок", "негритёнка", "негритят")} " +
"#{sklonenie(skolko, "пошел", "пошли", "пошли")} купаться в море!"
Мы здесь активно используем конструкцию "#{}"
для вставки значений в строку.
Обратите внимание, что слово «пошли» тоже зависит от количества — если 1, то пошёл, если 2 или 5, то пошли.
Важный нюанс для тех, кто хочет стать хорошим программистом. Делайте ваши методы надёжными.
Задумайтесь, что может плохого произойти, если вместо числа в наш новый метод sklonenie
передадут какую-нибудь строку или его вызовут вообще без параметров.
Очевидно, ничего хорошего из этого не выйдет, поэтому давайте сделаем в начале метод небольшую проверку и вручную приравняем number
нулю в этих двух случаях.
if (number == nil || !number.is_a?(Numeric))
number = 0
end
Для того, чтобы вспомнить, что за выражение стоит в скобках после if, вы можете посмотреть четвёртый урок: если вкратце, то это условие проверяет, лежит ли в number
пустота (nil
), проверяет, лежит ли в number
что-то, что не является числом и если хотя бы одно из этих условий выполнено, заходит в тело if
.
Обратите внимание на метод is_a?
. Он есть у любого объекта Ruby и возвращает true
, если объект принадлежит к указанному классу и false
, если не принадлежит.
puts [1,2,3].is_a?(Array)
puts "Строка".is_a?(String)
puts 28.is_a?(Numeric)
Выведет на экран true
три раза, а вот
puts "Я не число".is_a?(Numeric)
Выведет на экран false
.
Запустите программу и посчитайте негритят.
cd c:\rubytut\lesson9
ruby sklonenie.rb
Итак, в этом непростом уроке мы узнали чертовски важную вещь: как писать свои маленькие вспомогательные подпрограммы — методы. Узнали, с чем нужно определиться перед тем, как писать свой метод, когда их стоит использовать, а когда — нет, и зачем в программах нужны ключевые слова def
и return
.
А также попутно узнали про оператор %
и метод is_a?
.
Кстати, в написанной здесь программе про склонение слов есть несколько ошибок — она будет всегда выполняться, но не всегда будет давать верный результат. Интересно — найдете ли вы сами эти ошибки? В домашнем задании к уроку мы рассказываем об этих ошибках и исправляем их.
В следующем уроке мы соберём в охапку всё, что узнали на предыдущих уроках и напишем нашу первую серьёзную программу — игру «Виселица».