Привет всем. Недавно я начал более глубоко копаться в Ruby 2.0. Самая интересная особенность для меня — это добавление реальных аргументов ключевых слов. Когда я искал информацию о том, как другие языки реализуют и используют аргументы ключевых слов, я понял, насколько мощным является это дополнение. Короче говоря, это очень мощный.
Здесь я хочу обсудить, как Ruby позволяет устанавливать параметры, какие шаблоны следует Rubyists при создании методов, и, наконец, обсудить, насколько забавными и гибкими являются ключевые аргументы Ruby 2.0.
Часть из этого может быть элементарной для продвинутого разработчика, поскольку эта статья нацелена на помощь начинающему Rubyist. Тем не менее, я обнаружил, что присвоение имен некоторым концепциям, которые мы считаем само собой разумеющимся, может быть полезным даже для самых закаленных ветеранов.
В статье [1], опубликованной в 2009 году, Алан Скоркин классифицирует аргументы как:
- необходимые
- Необязательный
- Аргументы со значениями по умолчанию
Я думаю, что это хороший способ думать о том, как Ruby обрабатывает аргументы. Интересная часть здесь состоит в том, что все (или, по крайней мере, большинство) методов обработки аргументов в этой статье попадут в эти широкие определения. При этом некоторые, если не все, методы можно использовать друг с другом.
Например, у меня может быть метод с порядковыми аргументами, аргументами со значениями по умолчанию и аргументом хеш-функции. Ruby — мощный язык, и одной из его сильных сторон является гибкость. Убедитесь, что вы изучаете и используете эту гибкость в полной мере.
Вот список типов обработки аргументов, которые мы будем обсуждать и которые будут служить оглавлением для этого поста:
- Нет параметров
- Порядковые параметры
- Параметры со значениями по умолчанию
- Хэш-парам
- Аргументы как массив
- Ключевое слово Аргументы (Ruby 2.0)
Краткое введение
Прежде чем мы начнем, нам нужно установить правильный синтаксис создания метода. В Ruby методы объявляются ключевым словом def
После ключевого слова def
Соглашение устанавливает использование змеи-падежа для имен методов, которые содержат несколько слов. После имени метода мы передаем наши параметры в скобках. Ключевое слово end
class
module
def example_method(args); end
#
#OR
#
def example_method(args)
end
( рисунок а. )
Теперь, когда вы быстро перефразировали, мы можем начать говорить об обработке аргументов.
Нет параметров
Вероятно, это будет самый короткий раздел, потому что это наименее интересный путь. Вы определяете метод без аргументов и вызываете его без аргументов.
def example_method; puts "Hello, World."; end
#
example_method
#=> Hello, World
( рисунок б. )
Вот и все.
Порядковые параметры
Порядковые параметры называются так, потому что аргументы, передаваемые методу, должны отправляться в порядке, установленном в сигнатуре метода. Технически, порядок имеет значение для всех типов аргументов (кроме соло || без параметров). Однако, когда я здесь использую слово порядковый номер, я имею в виду обязательные параметры, передаваемые по порядку. Например:
def example_method(a,b)
puts a,b
end
#
# We must pass the arguments in proper order, so that they
# reference what we expect.
#
example_method("This is A", "This is B")
#=> This is A
#=> This is B
( рисунок с. )
Передача аргументов не по порядку не является синтаксической ошибкой, но внутри метода они будут ссылаться на значения при их отправке. Так как оба эти параметра являются обязательными, отсутствие двух аргументов вызовет ArgumentError
Параметры со значениями по умолчанию.
Ruby позволяет нам передавать значения по умолчанию в качестве параметров для методов. Сделать это довольно просто: внутри объявления метода используйте знак равенства ( =
Например:
def example_method(a,b="default_b_value")
end
( рисунок d. )
Поскольку b
example_method("a_value")
или example_method("a_value", "b_value")
Здесь example_method
Однако этот метод дает нам гораздо больший контроль над интерфейсом этого метода.
Хэш-параметры
В какой-то момент вы захотите иметь возможность обрабатывать произвольное количество аргументов для данного метода. Ruby предоставляет несколько способов сделать это. Самый распространенный способ указать произвольное количество аргументов — использовать хеш в качестве аргумента. Это создает что-то похожее на ключевые слова (которые мы обсудим более подробно позже). По правде говоря, я не уверен, что могу сказать, что это самый распространенный способ передачи аргументов, но он, безусловно, является фаворитом многих уважаемых Rubyists.
def example_method(options)
puts options[:message]
end
example_method({message: "Hello, World!"})
#=> Hello, World!
( рисунок е. )
Руби делает некоторые умные вещи здесь. Если ваш хэш опций является последним или единственным параметром, вы можете оставить скобки. Вот почему этот метод иногда называют аргументами «псевдо-ключевых слов», потому что он напоминает ключевые слова, но на самом деле просто скрывает хеш.
Приведенные ниже примеры иллюстрируют, как вы можете использовать это, чтобы написать несколько симпатичных методов.
# the above method could be called like so (in 1.9)
example_method(message: "Hello, World!")
( рисунок е.2. )
Или с параметрами в конце списка параметров.
def example_method(ordinal_a, ordinal_b, options)
p [ordinal_a, ordinal_b, options]
end
example_method("Yo", "Sup", message: "Hello, World!")
#=> ["Yo", "Sup", {:message=>"Hello, World!"}]
( рисунок е.3. )
Использование этого шаблона позволяет создавать красивые интерфейсы. Тем не менее, это не без недостатков. Ниже приведены несколько примеров аберрантного поведения (некоторые из которых облегчаются благодаря использованию аргументов ключевых слов в Ruby 2.0).
Если параметры имеют значения по умолчанию, но метод вызывается с передачей неожиданного значения (т. Е. Nil), то это значение будет использоваться без жалоб. В приведенном ниже примере мы ожидаем, что параметр options
Это приводит к ошибке.
def display_name(options={})
p options[:first_name]
end
display_name(nil)
#=> NoMethodError: undefined method `[]' for nil:NilClass
#=> from (pry):2:in `display_name'
( рисунок е.4. )
Здесь у нас есть хеш со значением по умолчанию для имени. Если мы передаем хэш, хэш по умолчанию игнорируется. Поскольку хэш по умолчанию игнорируется, ключ first_name
def display_name(options={:first_name => "George"})
p options[:first_name]
end
display_name(:last_name => "Jetson")
#=> nil
( рисунок е.5. )
Хорошо, так что есть проблемы. При этом существуют шаблоны, которые разработчики Ruby используют для устранения некоторых из этих недостатков. Давайте посмотрим на другой пример.
class HelloWorld
def initialize(options=nil)
options ||= {}
@message = opts.fetch(:message,"Hello, World!")
end
def to_s
puts @message
end
end
( рисунок е.6. )
Несколько вещей происходит в коде выше. Метод initialize устанавливает HelloWorld#new
{}
Это сделано для того, чтобы мы могли создать экземпляр этого объекта без передачи аргументов. Следующая интересная вещь, когда мы устанавливаем @message
Поскольку мы знаем, что аргумент #new
Hash
Так как мы хотим, чтобы HelloWorld
Hash#fetch
- Использование
Hash#fetch
Решает рисунок е.5 - Назначение параметров для nil, а затем явное переназначение его по умолчанию (
options ||= {}
Решает рисунок е.4
Аргументы как массив
Что делать, если я хочу передать в мой метод произвольное количество аргументов. Ну, это можно сделать с помощью оператора *
Оператор splat будет принимать произвольное количество аргументов и собирать их в виде массива. Поначалу это может показаться немного странным, давайте рассмотрим пример, чтобы закрепить эту мысль в наших умах.
def example_method(*args)
p args
end
-> example_method("argument_one", "argument_two")
#=> ["argument_one", "argument_two"]
( рисунок е. )
Вы можете вызывать этот метод с любым количеством аргументов (включая ни одного). Это позволяет нам делать некоторые причудливые вещи при вызове наших методов. Важным примечанием является то, что, поскольку оператор splat будет жадно захватывать все значения в (position..position+n)
Ключевое слово Аргументы (Ruby 2.0)
Вот где это становится хорошо. Вы можете начать использовать некоторые из новых функций Ruby 2.0. Чтобы использовать аргументы ключевых слов, вы должны указать их в подписи, используя новый (1.9) синтаксис хеш-стиля, хотя вы можете вызывать его в классическом стиле. Поскольку у нас есть приличное представление о том, как должны выглядеть ключевые слова (после просмотра стиля «псевдо-ключевых слов»), мы сразу перейдем к примеру.
Посмотрите на проблему на рисунке е.5 еще раз. В нем вы захотите установить значение по умолчанию для :first_name
:last_name
С помощью ключевых слов вы можете просто определить метод следующим образом:
def display_name(first_name: "George", last_name: "Jetson")
p "#{last_name}, #{first_name}"
end
display_name(last_name: "Jetson")
#=>
Этот метод может быть вызван любым из следующих способов:
display_name
#=> "Jetson, George"
#
display_name(first_name: "Judy")
#=> "Jetson, Judy"
#
display_name(last_name: "Jefferson")
#=> "Jefferson, George"
#
display_name(last_name: "Flinstone", first_name: "Fred")
#=> "Flinstone, Fred"
Чтобы повторить этот метод до Ruby 2.0, вам необходимо:
- По умолчанию параметр параметров
- Создайте хэш, заполненный вашими значениями по умолчанию
- Объединить параметры в хэш по умолчанию
Аргументы ключевых слов позволяют вам быть невероятно лаконичными при объявлении метода. В Ruby 2.0 метод создается, как указано выше, вместо более подробного эквивалента в 1.9.x:
def display_name(options=nil)
options ||= {}
{first_name: "George", last_name: "Jetson"}.merge(options)
p "#{last_name}, #{first_name}"
end
Если бы это был единственный способ использовать аргументы ключевых слов, я был бы продан, но это еще не все! БЛОКИ И ПРОЦЕССЫ! Скажем, вы хотите сделать display_name
Это так же просто, как:
display_name = Proc.new {|first_name: "George", last_name: "Jetson"| p "#{last_name}, #{first_name}" }
display_name.call
#=> "Jetson, George"
display_name.call(first_name: "Judy")
#=> "Jetson, Judy"
Аккуратно да ^ _ ^
Что произойдет, если вы передадите ключевой аргумент, который не указан в сигнатуре метода? Давайте взглянем.
def example_method(first_keyword: "example")
end
example_method(last_keyword: "Last")
#=> ArgumentError: unknown keyword: last_keyword
#...
Мы получаем ArgumentError
Если вы хотите получить доступ к этим неназначенным аргументам ключевых слов, вы можете использовать оператор **
def example_method(first_keyword: "example", **other_keywords)
p other_keywords
end
example_method(last_keyword: "test")
#=> {:last_keyword=>"test"}
Вывод
Рад, что ты сделал это так далеко. Я надеюсь, что вы сейчас так же взволнованы, как и я по поводу Ruby 2.0 Что еще более важно, я надеюсь, что это помогло вам лучше понять, как работает Ruby. Гибкая природа Ruby допускает некоторые дикие вариации даже в самых простых задачах. Это одно из самых сильных его достоинств и одна из причин, по которой я влюбился в язык.
Спасибо за прочтение.
Ссылки
- 2010, Алан Скоркин, «Аргументы метода в Ruby»
- Ruby-Doc, 1.9.3, «Hash # fetch» »
- 2011, Джейкоб Своннер, «Необязательный параметр Gotchas»
- 2012, Крис Цеттер, «Аргументы ключевых слов в Ruby 2.0»