Как установить значение по умолчанию для аргумента знака в Ruby

Установка значения по умолчанию для аргумента splat приводит к ошибке:

1.9.3-p374 :001 > def a b, *c = nil
1.9.3-p374 :002?>   end
SyntaxError: (irb):1: syntax error, unexpected '=', expecting ';' or '\n'
def a b, *c = nil
             ^
    from /Users/me/.rvm/rubies/ruby-1.9.3-p374/bin/irb:16:in `<main>'

Некоторые варианты, которые я пробовал, тоже не работают:

1.9.3-p374 :003 > def a b, *c = []
1.9.3-p374 :005 > def a b, (*c) = nil
1.9.3-p374 :007 > def a b, (*c = [])
1.9.3-p374 :009 > def a b, (*c = [1,2,3])
1.9.3-p374 :011 > def a b, *c = [1,2,3]

Я не вижу здесь проблемы неопределенности, поэтому кажется, что это должно быть возможно.

Связанный: Почему нет -explicit splat param plus default param — это неправильный синтаксис для определения метода в Ruby 1.9?


person jordanpg    schedule 03.04.2013    source источник
comment
Аргумент Splat по умолчанию является пустым массивом   -  person fl00r    schedule 04.04.2013
comment
Да, но как насчет аргумента по умолчанию?   -  person jordanpg    schedule 04.04.2013
comment
Есть ли причина, по которой вы еще не приняли ответ?   -  person vlasits    schedule 05.04.2013
comment
@vlasits Я надеялся, что кто-нибудь устранит техническую причину, по которой Ruby не позволяет устанавливать параметры по умолчанию для знаков обычным способом. Я читал, что вы сказали о том, что это дизайнерское решение.   -  person jordanpg    schedule 05.04.2013


Ответы (4)


Ваша попытка использования противоречит правилам использования знака. Предполагается, что знаки (по крайней мере, в Ruby) занимают все лишние (0, 1 или более) значения.

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

def a b, c=nil, *d 
  # rest of code omitted
end

EDIT: чтобы сделать ответ на ваш вопрос, почему это не работает, совершенно ясным. Это дизайнерское решение дизайнера языка. Мац никогда не предполагал, что оператор splat будет работать со значениями по умолчанию. Это кажется мне довольно разумным, поскольку он предназначен для использования для перехвата неопределенного числа переменных и потому, что описанный мной метод читается более четко, чем описанные вами возможности, и потому что все проблемы, которые решают ваши примеры, могут быть решены другими способами.

person vlasits    schedule 03.04.2013
comment
+1 Это правильный способ сделать это. Если c является таким особенным, продвиньте его к отдельной записи параметра и не играйте в игры, пытаясь извлечь его из переменной splatted. - person the Tin Man; 04.04.2013

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

def test(a, *b)
  b = "default b" if b == [] # edited as per Tin Man's recommendation
  puts [a, b].inspect
end

test("Test", 1, 2)
# => ["Test", [1, 2]]
test("Test")
# => ["Test", "default b"]

В Rails вы можете проверить b.present?, так как пустой массив считается пустым. Надеюсь, это поможет.

person Thomas Klemm    schedule 03.04.2013
comment
b == [] and b = "default b" не рекомендуется для стиля Ruby. Используйте b = "default b" if b == []. - person the Tin Man; 04.04.2013
comment
Спасибо, я включил ваше предложение. Есть ли за этим техническая причина? - person Thomas Klemm; 04.04.2013
comment
Это проблема читабельности и обслуживания. Использование логического значения для соединения условной проверки и присваивания во многом является конструкцией C/Perl; Это лаконично, почти загадочно, без заметной скорости, если таковая имеется. При написании на C или Perl ожидается, почти мачо, возможность писать так, но Ruby делает немного короче для большей удобочитаемости. Кроме того, если вы используете and, а затем добавляете дополнительные тесты или задания, порядок приоритета может вас укусить, что может быть очень сложно отследить. Использование && во многих случаях позволяет избежать проблемы приоритета, но не повышает читабельность. - person the Tin Man; 04.04.2013
comment
Большое спасибо @theTinMan за разработку! - person Thomas Klemm; 04.04.2013

Аргумент splat по умолчанию представляет собой пустой массив, и вам не нужно делать ничего особенного.

def a(b, *c)
  c
end

a("foo")
#=> []
person Wally Altman    schedule 03.04.2013
comment
Да, но как насчет аргумента по умолчанию, кроме nil? - person jordanpg; 04.04.2013
comment
Смотрите мой ответ, что делать, если вы хотите, чтобы c имело значение по умолчанию. - person vlasits; 04.04.2013

Это очень удобно:

def initialize(*response_names)
  @response_names = response_names.presence || %w(default values)
end
person Martin Streicher    schedule 09.02.2017