Строки
Для начала поговорим о строках. Мы рассмотрим:
- Различные виды строк, поддерживаемые Ruby
- Многие методы, поддерживаемые String API
- Символы
Строки с одной кавычкой очень буквальны. Они позволяют экранирование '
с помощью /
, и показывают всё остальное практически как есть.
Строки с двойными кавычками имеют специальные символы, которые они могут интерпретировать: /n
, /t
и другие.
Другая интересная функция, которую они имеют, это интерполяцию строк.
Строки / интерполяция
single_quoted = 'ice cream \n followed by it\'s a party!'
double_quoted = "ice cream \n followed by it\'s a party!"
puts single_quoted # => ice cream \n followed by it's a party!
puts double_quoted # => ice cream
# => followed by it's a party!
def multiply (one, two)
"#{one} умножить на #{two} равняется #{one * two}" # интерполяция доступна только для строк с двойными кавычками
end
puts multiply(7, 3)
# => 7 умножить на 3 равняется 21
Еще о строках:
- Строковые методы, заканчивающиеся на
!
, изменяют существующую строку - Большинство других просто возвращают новую строку
- Можно использовать
%Q{длинная мультистрочная строка}
- Ведет себя так же как и строка с двойными кавычками
my_name = " тим"
puts my_name.lstrip.capitalize # => Тим
# методы без ! выводят измененную копию строки
p my_name # => " тим"
my_name.lstrip! # убирает первый пробел
# метод с ! на самом деле изменяет строку
my_name[0] = 'К' # заменяет первый символ
puts my_name # => Ким
cur_weather = %Q{Сегодня жарко
Захватите зонтики...}
cur_weather.lines do |line|
line.sub! 'жарко', 'дождливо' # заменяет "жарко" на "дождливо"
puts "#{line.strip}"
end
# => Сегодня дождливо
# => Захватите зонтики...
API строк
https://ruby-doc.org/core-2.4.1/String.html
Здесь есть много хороших примеров.
Символы
Другой тип строк, который многих удивляет, — это идея символа.
Итак, что такое символ? Символ — это двоеточие, за которым следует некоторая строка.
К примеру, :foo-
. Символы — это просто оптимизированные строки.
У них гораздо меньше методов, чем у (обычных) строк, и они действительно служат другой цели. Это постоянные имена, которые вам не нужно объявлять.
Символы гарантированно будут уникальными и неизменными. Они могут быть конвертированы в Строку с помощью to_s
, или со Строки в Символ с помощью to_sym
.
Символ может являться репрезентацией имени метода.
Так, к примеру, на любом объекте в Ruby вы можете просто спросить, какие у меня методы? И он предоставит вам все методы, поддерживаемые этим объектом.
В этом случае мы делаем чуть больше, мы ищем методы со словом case.
Интересно, что мы видим обычную версию метода и версию с !
, которая изменяет строку безвозвратно.
Массивы
Далее мы обсудим массивы (множества):
- Как они создаются
- Как изменять массивы
- Доступ к элементам внутри массива
Вы могли познакомиться с массивами в других языках программирования, и Ruby также отлично поддерживает их, как мы увидим.
Массивы:
- Коллекция ссылок на объекты
- Индексируется с использованием оператора
[]
- Может индексироваться с отрицательными числами или диапазонами
- В одном массиве разрешается иметь различные типы данных
- Можно использовать
%w{str1 str2}
для создания массива строк
het_arr = [1, "два", :три] # различные типы
puts het_arr[1] # => два (индексы массива начинаются с 0)
arr_words = %w{ какой же сегодня хороший день! }
puts arr_words[-2] # => хороший
puts "#{arr_words.first} - #{arr_words.last}" # => какой - день!
p arr_words[-3, 2] # => ["сегодня", "хороший"] (вернуться на 3 элемента назад и взять 2 из них)
# (Диапазон, который мы рассмотрим позже...)
p arr_words[2..4] # => ["сегодня", "хороший", "день!"]
# Сделать строку из элементов массива, разделенных ','
puts arr_words.join(',') # => какой,же,сегодня,хороший,день!
Изменение массивов:
- Добавление:
push
или<<
- Удаление:
pop
илиshift
- Задать конкретный элемент: метод
[]=
Другие функции:
- Показать случайный элемент(ы) с помощью
sample
- Сортировать или реверсировать массив с помощью
sort!
иreverse!
Скажем, у вас есть сотня элементов, и вы говорите, дай мне пять элементов из этого массива в качестве примера. Это отлично подходит для тестирования, как и функция, позволяющая сортировать или реверсировать массив.
И аналогично строкам у вас есть либо сортировка без восклицательного знака, либо сортировка с ним. Как вы догадались, способ без !
возвращает отсортированную копию массива, а способ с !
изменяет сам массив.
# Вам нужен стек? Без проблем
stack = []; stack << "один"; stack.push ("два")
puts stack.pop # => два
# Вам нужна очередь? Тоже есть
queue = []; queue.push "один"; queue.push "два"
puts queue.shift # => один
a = [5,3,4,2].sort!.reverse!
p a # => [5,4,3,2] (фактически изменяет массив)
p a.sample(2) # => 2 случайных элемента
# Что будет, если добавить 33 как шестой (седьмой, считая с 0) элемент?
# Массив автоматически расширится и добавит nil вместо пустых элементов
a[6] = 33
p a # => [5, 4, 3, 2, nil, nil, 33]
Другие полезные методы:
each
— перебирает массивselect
— фильтрует массив, выбираяreject
— фильтрует массив, отклоняяmap
— изменяет каждый элемент в массиве
API массивов.
Много других полезных методов можно найти, посмотрев API массивов: https://ruby-doc.org/core-2.4.1/Array.html
Давайте посмотрим некоторые примеры методов, которые я упомянул выше.
a = [1, 3, 4, 7, 8, 10]
a.each { |num| print num } # => 1347810 (нет новой строки)
puts # => (с новой строки)
new_arr = a.select { |num| num > 4 }
p new_arr # => [7, 8, 10]
new_arr = a.select { |num| num < 10 }
.reject{ |num| num.even? }
p new_arr # => [1, 3, 7]
# Умножить каждый элемент на 3, создав новый массив
new_arr = a.map {|x| x * 3}
p new_arr # => [3, 9, 12, 21, 24, 30]
В итоге.
Таким образом, API массивов очень гибкий и очень мощный. Я просто показал несколько методов, но есть еще многие, которые могут быть полезными. И есть много способов обработки элементов.
Далее мы собираемся рассмотреть диапазоны.
Диапазоны
Поговорим о диапазонах и о том как они полезны в Ruby.
Итак, диапазоны — это по сути тип данных в Ruby, который используется для выражения естественных последовательностей.
1..20
,'a' .. 'z'
Есть два правила, которые следует иметь в виду. Если используется две точки между началом и концом, то это означает, что всё включено.
К примеру, в 1..10
включается 1, включается 10 и, очевидно, всё что между ними.
Если используется три точки, к примеру 1...10
, то последняя цифра исключается. То есть, в этом примере будет включено 1, включено 1-9, но 10 исключено.
Можно легко это запомнить как "чем больше точек у вас есть, тем меньше включено в конце". Хотя это слегка нелогично, но таким образом это легко запомнить.
—
Что такого особенного в диапазонах? Разве мы не можем сделать это с помощью массивов?
В первую очередь, их очень легко создать, вам просто нужна первая и последняя часть последовательности.
Кроме того:
- Диапазоны очень эффективны
- Могут быть конвертированы в массив с помощью
to_a
- Используются для условий и интервалов
Скажем, у вас есть последовательность из чисел от одного до миллиона, вы не собираетесь хранить миллион элементов вашего массива в памяти. Вы просто храните первое число и последнее число, что здорово.
Если вам нужно больше методов для этого диапазона, вы всегда можете преобразовать его в массив, вызвав метод to_a
.
И еще одна причина по которой используются диапазоны, наверное самая частая, это условия и интервалы, которые мы рассмотрим в примере ниже.
some_range = 1..3
puts some_range.max # => 3
puts some_range.include? 2 # => true
puts (1...10) === 5.3 # => true
puts ('a'...'r') === "r" # => false (конец исключается)
p ('k'..'z').to_a.sample(2) # => ["k", "w"]
# или другой случайный массив с двумя буквами из диапазона
age = 55
case age
when 0..12 then puts "Еще ребенок"
when 13..99 then puts "Молод в душе!"
else puts "Вы становитесь старше..."
end
# => Молод в душе!
В итоге.
Диапазоны полезны при использовании последовательностей. Вы можете конвертировать диапазон в массив, если требуется получить больше функциональности.
Хэши
Теперь поговорим о хэшах.
Как они используются, зачем они используются, и есть ли у них схожести с блоками.
Хэши:
- Индексированные коллекции ссылок на объекты
- Создаются с помощью
{}
илиHash.new
- Также известны как ассоциативные массивы
- Индекс (ключ) может быть чем угодно
- А не только целым числом, как в случае с массивами
Также:
- Доступны с помощью оператора
[]
- Значения задаются с помощью:
=>
(создание)[]
(после создания)
Давайте взглянем на пример.
editor_props = { "font" => "Arial", "size" => 12, "color" => "red"}
# Выше указан не блок, это хэш
puts editor_props.length # => 3
puts editor_props["font"] # => Arial
editor_props["background"] = "Blue"
editor_props.each_pair do |key, value|
puts "Ключ: #{key}, значение: #{value}"
end
# => Ключ: font, value: Arial
# => Ключ: size, value: 12
# => Ключ: color, value: red
# => Ключ: background, value: Blue
—
Что будет, если вы попытаетесь получить доступ к значению в хэше, для которого нет записи? В этом случае вернется nil
.
Если хэш был создан с помощью Hash.new(0)
(0 в качестве примера), то будет возвращен 0
.
—
API хэшей.
API хэшей тоже полезно освоить: https://ruby-doc.org/core-2.4.1/Hash.html
—
К примеру, используя синтаксис Hash.new со значением 0, мы хотим рассчитать частоту слов. Скажем, у нас есть предложение с какими-то словами, каждое из которых повторяется дважды.
word_frequency = Hash.new(0)
sentence = "Chicka chicka boom boom"
sentence.split.each do |word|
word_frequency[word.downcase] += 1
end
p word_frequency # => {"chicka" => 2, "boom" => 2}
Еще о хэшах
В текущей версии Ruby, порядок записей в хэшах сохраняется.
При использовании символов в качестве ключей, можно использовать синтаксис symbol:
.
Если хэш является последним аргументом метода, {}
являются опциональными.
Давайте взглянем на всё это в примере.
family_tree_19 = {самый_старший: "Джим", старший: "Джо", младший: "Джек"} # хэш
family_tree_19[:самый_младший] = "Джереми"
p family_tree_19
# => {:самый_старший=>"Джим", :старший=>"Джо", :младший=>"Джек“, :самый_младший => “Джереми”}
# порядок поддерживается
def adjust_colors (props = {foreground: "красный", background: "белый"})
puts "Передний план: #{props[:foreground]}" if props[:foreground]
puts "Фон: #{props[:background]}" if props[:background]
end
adjust_colors # => Передний план: красный
# => Фон: белый
adjust_colors ({ :foreground => "зеленый" }) # => Передний план: зеленый
adjust_colors background: "желтый" # => Фон: желтый
adjust_colors :background => "фиолетовый" # => Фон: фиолетовый
Путаница между хэшами и блоками
Это происходит не слишком часто, но иногда начинающие разработчики допускают ошибку.
# Скажем, у вас есть хэш
a_hash = { :one => "one" }
# Затем вы выводите его
puts a_hash # => {:one=>"one"}
# Если вы попытаетесь сделать это за один шаг - вы получите SyntaxError
# puts { :one => "one" }
# Ruby путается и думает, что {} является блоком!!!
# Чтобы обойти это, вы можете использовать скобки
puts ({ :one => "one" }) # => {:one=>"one"}
# Или вообще отбросить {}...
puts one: "one" # => {:one=>"one"}
В итоге.
Хэши являются индексированными коллекциями. Их использование очень похоже на использование массивов.
Хотя это не является частым, хэши могут быть спутаны с блоками, так что следует быть осторожным с этим.