Методы Ruby и упорядочение нескольких значений по умолчанию - PullRequest
6 голосов
/ 03 марта 2010

Кажется, я не могу этого сделать (что я имел обыкновение делать в Python). Позвольте мне объяснить ..

Предположим, у меня есть следующий метод в Ruby:

def someMethod(arg1=1,arg2=2,arg3=3)
...
...
...
end

Теперь для вызова этого метода я мог бы сделать

someMethod(2,3,4)
someMethod(2,3)
someMethod(2)

и аргументы принимаются в соответствующем порядке ... но что, если я захочу дать arg2 в какой-то момент моего программирования и получить значения по умолчанию для arg1 и arg3?

Я пытался написать someMethod (arg2 = 4), но, похоже, это не работает в Ruby 1.9. Что он делает, так это все еще думает, что arg1 равен 4. В python я мог бы по крайней мере сойти с рук, но в ruby ​​я не уверен. У кого-нибудь есть изящные идеи?

Ответы [ 3 ]

13 голосов
/ 03 марта 2010

На данный момент единственным элегантным решением является использование хеша в качестве списка параметров:

def some_method(options = {})
  defaults = {:arg1 => 1, :arg2 => 2, :arg3 => 3}
  options = defaults.merge(options)
  ...
end

и более поздние версии в коде используют неявный хеш при вызове вашего метода:

some_method()
some_method(:arg1 => 2, :arg2 => 3, :arg3 => 4)
some_method(:arg2 => 4)

В Ruby 1.9 вы можете использовать новый синтаксис ключей хеша, чтобы получить больше как в Python:

some_method(arg1: 2, arg2: 3, arg3: 4)

Если вы хотите более простой синтаксис и все еще можете использовать позиционные параметры, тогда я бы предложил поиграть с чем-то вроде этого:

def some_method(*args)
  defaults = {:arg1 => 1, :arg2 => 2, :arg3 => 3}
  options = args.last.is_a?(::Hash) ? args.pop : {}
  options = defaults.merge(options)

  arg1 = args[0] || options[:arg1]
  arg2 = args[1] || options[:arg2]
  arg3 = args[2] || options[:arg3]
  ...
end

some_method()
some_method(2)
some_method(3,4,5)
some_method(arg2: 5)
some_method(2, arg3: 10)

Если вы хотите имитировать проверку числа аргументов Ruby для метода, вы можете добавить:

fail "Unknown parameter name(s) " + (options.keys - defaults.keys).join(", ") + "." unless options.length == defaults.length

EDIT:
Я обновил свой ответ комментарием Jonas Elfström

2 голосов
/ 03 марта 2010

В Ruby отсутствует передача аргументов по ключевым словам. (Пока нет, во всяком случае, это одна из вещей, которая может превратить его в Ruby 2.0. Однако, нет никаких гарантий, и работа над Ruby 2.0 еще даже не началась , так что неизвестно, когда или даже если мы увидим ключевые аргументы в Ruby.)

Что действительно происходит , так это то, что вы передаете выражение arg2 = 4 в качестве единственного аргумента в списке аргументов. Ruby - это строгий язык с передачей по значению, что означает, что все аргументы полностью оцениваются перед их передачей в метод. В этом случае arg2 = 4 является выражением присваивания (в Ruby все является выражением (т. Е. Все возвращает значение), операторов нет). Вы присваиваете непосредственный литерал Fixnum значение 4 локальной переменной arg2. Выражения присваивания всегда возвращают значение их правой части, в данном случае 4.

Итак, вы передаете значение 4 как единственный аргумент в ваш метод, что означает, что он привязывается к первому обязательному параметру, если он есть (в данном случае его нет), в противном случае к первый необязательный параметр (в данном случае arg1).

Обычный способ справиться с подобными ситуациями - вместо этого использовать Hash, например:

some_method({:arg2 => 4})

Поскольку этот шаблон используется так часто, существует особая синтаксическая поддержка: если аргумент last для метода равен Hash, вы можете оставить фигурные скобки:

some_method(:arg2 => 4)

В Ruby 1.9 есть еще одна синтаксическая удобная форма: поскольку Hash часто используются с Symbol ключами, для этого существует альтернативный буквенный синтаксис Hash:

some_method({arg2: 4})

Объедините их обоих, и у вас почти будут ключевые аргументы:

some_method(arg2: 4)

(На самом деле оба эти ярлыка были специально добавлены, чтобы обеспечить легкий путь перехода к возможным будущим версиям Ruby с аргументами ключевых слов.)

MacRuby фактически поддерживает многочастные селекторы сообщений в стиле Smalltalk для взаимодействия с Objective-C. Обратите внимание, однако, что селекторы многочастных сообщений в стиле Smalltalk являются , а не аргументами ключевых слов, они ведут себя совершенно по-разному. Также, конечно, это расширение относится только к MacRuby и не входит в спецификацию Ruby и не переносимо на MRI, YARV, JRuby, XRuby, IronRuby, MagLev, Rubinius, tinyrb, RubyGoLightly, BlueRuby, SmallRuby или любую другую реализацию Ruby.

2 голосов
/ 03 марта 2010

Для того, что вы пытаетесь сделать, лучше всего использовать хеш как единственный аргумент.

def someMethod(args={})
args[:arg1] ||= 1
args[:arg2] ||= 2
args[:arg3] ||= 3
...

Этот метод затем будет вызываться так

someMethod(:arg1 => 2, :arg3 => 5)

все не установленные хеш-значения будут заменены их значениями по умолчанию (например, arg2 = 2).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...