10 января 2009 в 00:08

Покорим Ruby вместе! Капля третья

Капаем дальше. В третьей капле (капля первая, капля вторая) мы познакомимся с числовыми переменными и узнаем о принципах ООП.

Числа и Выражения


В программировании выражением (expression) называется комбинация чисел, операторов и переменных, которая, будучи понята компьютером, дает результат в какой-либо форме. Вот несколько примеров:

8
2 + 3
"a" + "b" + "c"
100 - 5 * (2 - 1)
x + y


Рассмотрим и разберем простой код:

x = 5
y = x * 20
x += y
puts x


Придаём переменной x значение 5, для y устанавливаем значение x * 20 (100). Затем прибавляем y к x и выводим результат. Все передельно ясно, единственная заминка может возникнуть на третьей строке. Казалось бы адекватнее написать x = x + y, однако это — кусочек сахара Ruby. Также можем использовать x *= y и x /=, а x += 1 увеличит переменную на единицу.

Операторы сравнения и Условия

Еще код:

age = 22
puts "Sovsem Molodoi!" if age < 25


Компьютер не только выполняет заданные операции (иначе это был бы просто калькулятор), он использует логику для определения направления работы. Результат исполнения кода предсказуем. Разберем вторую строку. Прежде всего обратим внимание на age < 25 — известные всем «больше/меньше» (а также ==, >=, <=, <=>, !=) работают и в Руби. Дальше видим знакомое из других языков условие: if. А где же then, end? Еще один сахарок Руби, на самом деле вторая строка полностью аналогична коду:

if age < 25 then
puts "Sovsem Molodoi!"
end


Условия можно комбинировать. Чтобы получить противоположный эффект можно использовать слово unless:

age = 24
puts "You're NOT a teenager" unless age > 12 && age < 20


Код понятен. Идем дальше.

Итераторы

Вот что ожидает нас здесь:

4.times do puts "Ruby" end

Давайте попробуем запустить код — результатом будет четырёхкратное выполнение puts. Анализируем. В первую очередь берётся число 4, затем для него вызывается метод times, применимый ко всем числам в Руби (метод? что такое метод? это действие — об этом поговорим позже). Вместо того, чтобы передавать в метод данные, мы передаём ему код, находящийся между do и end. Метод times затем 4 раза выполняет этот самый код. Как всегда Руби хочет, чтобы нам было удобнее писать программки, и поэтому дает еще одно послабление. Полностью аналогичный код, без do и end:

4.times { puts "Ruby" }

В Руби (да и в других ЯП тоже) одним из механизмов создания циклов является итератор — это некий объект, который позволяет перебирать все элементы какого-либо набора. В нашем случае он задает цикл, или итерирует, в четыре повтора. Посмотрим другие итераторы, применимые к числам в Руби:

1.upto(5) { ...код цикла... }
10.downto(5) { ...код цикла... }
0.step(50, 5) { ...код цикла... }


Думаю, назначение каждого из них понятно. Снова код:

1.upto(5) { |number| puts number }

В результате программа «посчитает до пяти» — мы передали состояние итерации в код. В начале циклируемого кода число «от 1 до 5» отправляется в переменную number.

Плавающая точка

Наверняка вы заметили, что во всех написанных ранее программах нам не приходилось объявлять переменные, определять их тип — Руби делает это за нас (продолжаем лизать сахар). Попробуем разделить: puts 10 / 3. Результат — 3. Так как входящие числа целые, то и результат остался целым. Руби хотел помочь, но у него не получилось. Давайте подскажем ему: puts 10.0 / 3.0. Решение оказалось простым!

Иногда мы оказываемся в такой ситуации, что не можем контролировать входящие числа, однако и тут есть решение:

x = 10
y = 3
puts x.to_f / y.to_f


Для целых чисел есть специальный метод (т.е. действие) .to_f, преобразующий их в числа с плавающей точкой на лету. Обратное действие (округление до целой части) выполняет метод .to_i.

Немного об ООП


В прошлой капле я говорил о том, что нам пока удается уходить от ООП. На самом деле я лукавил — в Руби всё, с чем мы манипулируем — это объекты. ВСЁ! Это отличает язык от C++ и Java, где присутствуют примитивные типы и фразы, не возвращающие значения.

При написании кода на Ruby, как и любого другого ОО кода, мы прежде всего создаем модели, а не пытаемся повторить весь процесс в коде. Например, если вам нужно написать приложение для кулинарной книги, вы, скорее всего, захотите создать список рецептов. Для моделирования вам придется использовать некоторые способы сортировки, чтобы воспроизводить различные виды данных, синхронизировать позиции необходимых данных в каждом списке и др. нонсенс. ООП делает работу легче, предлагая вам создавать классы и объекты, чтобы моделировать необходимые составляющие. В нашем примере вы можете создать класс Рецепты со строчными атрибутами название и автор и атрибутом в виде массива ингридиенты. Назначение класса — моделировать какую-либо вещь в вашей программе. Класс — это прототип, чертёж «существительных» в вашем прокте: объектов. Экземпляры класса или объекты (взаимозаменяемые термины) затем берут эти прототипы и запускают их в действие. В примере объекты могут быть созданы для каждого рецепта в списке, которые будут экземплярами класса Рецепты, который в свою очередь будет содержать данные и делать вещи, относящиеся к рецептам (например, держать список ингридиентов, добавлять ингридиенты в этот список, и т. п.) и следить за целостностью рецептов (например, что только числа в количествах ингридиентов, что каждый рецепт должен иметь название и др.) — все эти действия над объектами, «глаголы», и есть методы.

Вернемся к началам этой капли. Да, действительно, любое число — также полноценный объект. В примере 4.times {puts "Ruby"} число 4 — объект, является экземпляром класса Integer (мы об этом не заявляем в коде, Руби делает это за нас), к нему применяется метод times, который прописан в классе (опять мы этого не видим, но это подразумевается). Более того, даже в выражении x = 1 + x единица — это объект, а + — его метод! Вот так, не зная принципов ООП, мы уже, сами того не заметив, стали «жертвами» объектно-ориентированного программирования :)

Хватит — капля получилась хорошая, крупная, она дала нам все неоходимое, чтобы всерьёз переходить к реализации ООП на Ruby, что даст нам возможность двигаться дальше!

Как всегда жду ваших замечаний, отзывов и комментариев!

C четвертой каплей немного промазал, и она оказалась закопана под другими статьями — но она есть ;) ЗДЕСЬ!
Макс Креминский @MaxElc
карма
101,7
рейтинг 0,0
Похожие публикации
Самое читаемое Разработка

Комментарии (69)

  • 0
    И снова спасибо Вам!
  • +1
    Быстро вы )
    • 0
      Для себя и вас стараюсь ;)

      Кстати, вопрос к профи: Как отображать кириллицу в дебаггере (консольке) в Visual Studio? Сейчас там вопросы одни :(
      • 0
        Я не профи в VS, но по общим принципам найди где-нибудь в свойствах файла или в меню вид, где задается кодировка этого файла. Скорее всего VS поставила windows-1251 кодировку, а в консольке отоброжает utf-8, исправь кодировку файла на utf-8. Кроме того должна быть в свойствах проекта или настройках всей IDE кодировка по умолчанию для новых файлов.

        P.S. Можно, наверное, и вывод консоли настроить на windows-1251, но в наше время, по-моему правильно все на utf-8 настраивать изначально (учти это, кстати, когда начнешь с мускулом работать, чтобы и сам мускул по умолчанию utf-8 использовал, и приложения/IDE к нему коннектились с utf-8)
      • –2
        $KCODE = 'utf8'
        puts "привет"

        Код должен быть тоже в utf-8
        И вообще бросайте вы эту не провославную M$VS.
      • –1
        ты не как не сделаешь чтобы там нормально кириллица была, этим вопросом я занимался (насколько я знаю в linux все в порядке с ней). нормально русский язык отображается в начиная с ruby-1.9.0-2 (поскольку внедряется юникод), если не веришь мне скачай www.garbagecollect.jp/ruby вот тут (всегда самые новые версии ruby здесь есть, а 1.9.0-2 есть и для windows), да скажете вы выходила же версия Preview 1 для win, но там почему то кирилица не поддерживалась.
        • 0
          найдено решение надо ставить $KCODE = «u» и все будет нормально с кирилицей, проверено в netbeans и в intype, $KCODE = 'utf8' < — это вообще гон какой то.
          • 0
            пардон, там не «u» а 'u' (кавычки)
        • 0
          и ты здесь! =) все таки я начал читать и пытаться на руби колбасить!
  • 0
    age = 22
    puts "Sovsem Molodoi!" if age < 25


    Непривычно конечно, но после обратной польской нотации и не к такому можно привыкнуть :)

    Вот только не понял, что является ограничителем «спереди», как разделяются age = 22 и puts «Sovsem Molodoi!» начало строки или просто минус одно выражение перед if? В «сиобразных» языках по традиции для разделения используется ";", условные ветвления, циклы и прочее в большинстве случаев оперируют или одним выражением ( if (1 < 0) puts('1 < 0'); puts( '1 > 0'); выведет 1 > 0), или блоком выражений заключенным в скобки ( if (1<0) { puts('1<0'); puts ('1>0'); } не выведет ничего), а символ перевода строки приравнен к пробельным символам. А в Ruby что является разделителем?

    A пост- и прединкрменты/декременты есть? можно вместо x+=1 писать x++ или ++x?

    P.S. Молодец, видать вдохновение нашло от того, что язык понравился :)
    • +2
      В Ruby разделитель — новая строка
      • 0
        спасибо, пойду экспериментировать
      • +1
        и; тоже
    • –1
      Всё-таки определись, является Ruby и программирование на нем объектно-ориентированным или объектным. Сдается мне, что второе
      • 0
        Как мне подсказывали программирование на Ruby объектно-ориентированной, а язык просто нельзя так называть, язык объектный, а программирование ОО. Может я не так понял, конечно
      • 0
        Язык — объектный, так как все есть объект.
        А программирование на нем — это как получиться, пишем тоько процедуры — будет процедурное, строим иерархию классов — будет ООП, используем везде лямбду будет(правда очень своеобразное) функциональное программирование. От программиста вобщем зависит:)
    • +1
      Можете писать несколько операций на одной строке разделяя их точкой-с-запятой:
      puts «Hello »; puts «VolCh»

      Есть прединкремент:
      3.next
      • 0
        насчет разделения я уже догадался, и случанйо понял что в конструкции if then else end необязательно then
        сейчас вот никак не могу понять как сделать«обратную» форму записи полной конструкции пробую и puts "..." if a>0 puts "////" else и puts "..." else puts "////" if a>0 в общем все перестановки пытаюсь пробовать, хоть программу пиши :(
        • +1
          никак, исключительно из эстетических соображений, ну кроме тернарного оператора:
          condition ? if-expression : else-expression 
          
          • 0
            я правильно понимаю, что, например, puts тоже возвращает какое-то значение и можно написать, скажем
            num == 0 ? puts "Zero!!!" : puts num (понятно, что можно и короче записать, вынести puts «за скобки»)?
            • 0
              А можно ещё puts (num==0? «Zero!!!»: num)

              Упомяните в четвертой капле про break внутри итераторов и циклов. Там ещё такой момент, что, например, each возвращает то, по чем ходили, а while возвращает false (который то же самое, что nil).

              Пример использования (не наглядный, кому-то покажется ужасным, но главное, что виден принцип):
              puts ((2...x).each { |i| break nil if x%i==0 }? «простое»: «не простое»)
          • 0
            Кажется вопрос снимается, прочитал ответ нижу, если уж if и while значения имеют :)
            • 0
              метод всегда возвращает последнее вычисленное выражение за исключением случаев с return
              puts возвращает соответственно nil
        • 0
          then нужен в принципе чтобы переносить, выполняемый по условию, код на другую строку
          только в пределах одной строки можно обойтись без then
    • +2
      пост- и прединкрментов/декрементов нету
      • 0
        Да ладно вам. Что вы такое говорите?

        3.next # => 4
        «a».next # => b
        • +1
          Или это не инкремент, или после этого 3 == 4
          • 0
            Согласен. Действительно

            k = 3
            k.next # => 4

            но после этого
            puts k # => 3

            Как-то меня переклинило… :)
    • 0
      Декремента и инкремента в руби нет
      • 0
        кто мешает определить?

    • +1
      Это как-раз нормальное для человека построение предложения: «напечатай Sovsem Molodoi! если возраст меньше 25».
  • 0
    Скажите, а в каком случае какой «Операторы сравнения и Условия» надо использовать? Хотя это и не «операторы» вовсе.
    • 0
      Ой, это просто так слилось по смыслу :( Скажем так: «Условия и операторы сравнения»
      • 0
        Ну так а когда какой из 3х видов if-сахара используется? Когда программисту вздумается?
        • 0
          Что лучше читается, то и используется. Есть некоторые эмпирически выработанные критерии того, что читается лучше, а что хуже, но вообще — да, дело вкуса и личного стиля.
          • 0
            Обожаю руби за то, что на нем можно любое элементарное решение записать одним из сотни способов, которые глазу приятней.
    • 0
      Ну вообще говоря if, for, while, etc возвращают значения и их можно теоретически использовать в выражениях (но это изврат конечно)
      А вот в форме:

      variable = if condition
                       some_value
                     else
                       other_value
                     end
      

      встретить вполне можно.
      • 0
        Это не изврат, это нормально.

        Как раз наоборот, statement'ы это большое недоразумение.
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      Точно, аж самому противно :))
  • +2
    Как-то мне слово «инстанс» не нравится. Может лучше использовать «экземпляр»: метод экземпляра, экземпляр класса,…?

    В работе с float небольшая неточность: для того чтобы избежать целочисленного результата достаточно чтобы хотя бы одно число (делитель или делимое) было float. Не обязательно переводить во float оба числа.
    • 0
      Здорово, что вы подсказали с экземпляром — меняю в срочно порядке :)
  • 0
    Если про ООП как вам такой код:

    puts «1 + 2 = » + 1.+(2).to_s

    В Ruby все является объектом. И цифра «1» тоже объект и у него есть метод "+"
    • 0
      Да, хотел об этом написать, но как-то забыл — попробуем засунуть инфу ;)
    • –1
      да уж, надеюсь на практике такое не часто встречается? :)
    • 0
      Это пример не на объекты, а не передачу сообщений. ^_^
  • 0
    А какже про:

    case value
       when expression
            code
       .
       .
       .
    end
    
    • 0
      Еще вернемся к условиям :) Честно говоря и if сюда был засунут только для того, чтобы >< показать…
      • 0
        Ждем 4-ю каплю :)
  • +1
    4 — объект (...), к нему применяется метод times,

    Метод times — это неотъемлемая часть объекта 4, он является методом класса Fixnum.
    При вашей же формулировке, это не очевидно, создаётся впечатление, что метод times что-то чужеродное для него.
    Кстати, это очень легко проверить, в irb введите
    puts 4.methods.sort
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      Черт, а вот это я уже действительно проштрафился — придется писать в следующей «капле» :(
  • 0
    спасибо вам снова, ждем продолжения. Что то руби становится все ближе.
    Поделился камрой. (Max frei ©)
  • 0
    отлично! продолжайте. про замыкания напишите, хотелось бы разобраться получше
  • +1
    Вы собрались пересказать весь туториал?
    • +1
      Вообще то да. Кстати, если кто против — я буду оставлять топики в личном блоге
    • +1
      — Вы собрались пересказать весь туториал?
      а почему бы и нет? довольно интересно «пересказывается»
  • 0
    спасибо! у вас отлично это получается :)
  • 0
    Обычно подобные обсуждения встречаются в study-groups, когда люди обсуждают главу книги. Тут такое же впечатление. Не стоило переписывать учебник. Хотя, поделиться опытом даже в таких простых вещах — полезно.
    • 0
      На самом деле я только в этой статье позволил себе немного расслабиться и поцитировать книгу :)
      • +2
        Не останавливайтесь. Вы поможете многим и многим разработчикам :) Спасибо вам.
  • 0
    1. Что значит оператор сравнения <=>?
    2. Можно к существующим базовым классам добавить свои методы? Я имею в виду чтобы было 4.my_method
    3. Он вообще case-sensitive? myVar и Myvar — разные переменные?

    • +1
      1. Возвращает 0 если переменные равны, 1, если первая больше, -1 — соотвественно меньше
      2. Да, можно добавлять и изменять — об этом дальше.
      3. Да, однако переменные только со строчной буквы
  • –1
    Условия можно комбинировать. Чтобы получить противоположный эффект можно использовать слово unless:

    age = 24
    puts «You're NOT a teenager» unless age > 12 && age < 20


    Прошу прощения за возможно глупый вопрос (я совсем недавно начал переход на Ruby), а почему нельзя для того же эффекта написать

    puts «You're NOT a teenager» if age > 12 && age < 20

    Можете конкретнее пояснить разницу между unless и if?
    • 0
      Я так понимаю unless — «только если не»
      то есть
      unless = if not

      (я предположил, в руби не силен)
      • 0
        Я тоже так понимаю эту конструкцию.
        В контексте приведённого примера логично.

        Просто хотел уточнить. Спасибо :)
        • +1
          Более очевидна, по-моему, польза не со сложными выражениями, а с единичными булевыми переменными (или методами возвращающих true/false/nil)

          puts «error» unless success
        • –1
          puts «Гавно» unless «Сделано в Студии Артемия Лебедева»
          • 0
            Хороший пример :)

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.