2017-01-31 2 views
5

Я изучаю Руби в данный момент, и я столкнулся с этой странной ситуацией.Почему я получаю ошибку «Неожиданная *» при использовании оператора * (звездочка) в качестве параметра метода?

Когда я запускаю следующий код, я получаю вывод, показанный ниже.

Рабочий код:

def hello(a,b=1,*c,d,e,f) 
    p a,b,c,d,e,f 
end 

hello(1,2,3,4,5) 

Рабочий код выхода:

1 
2 
[] 
3 
4 
5 

Однако при редактировании кода, так что параметр 'е' улов всех параметров, я получаю ошибка, показанная ниже.

В противном случае код:

def hello(a,b=1,c,d,*e,f) 
    p a,b,c,d,e,f 
end 

hello(1,2,3,4,5) 

При отсутствии кода выхода:

a.rb:1: syntax error, unexpected * 
def hello(a,b=1,c,d,*e,f) 
        ^
a.rb:1: syntax error, unexpected ')', expecting '=' 
a.rb:3: syntax error, unexpected keyword_end, expecting end-of-input 

Я использую рубин 2.3.1p112 (2016-04-26 ревизии 54768) на Ubuntu.

Мне интересно узнать, почему второй фрагмент кода не работает.

Edit:

Следующий код не так.

def hello(a,b=1,c,d,e,*f) 
    p a,b,c,d,e,f 
end 

hello(1,2,3,4,5) 

И я получаю подобную ошибку

a.rb:1: syntax error, unexpected * 
def hello(a,b=1,c,d,e,*f) 
        ^
a.rb:3: syntax error, unexpected keyword_end, expecting end-of-input 
+2

Использование оператора splat не в конце для меня не имеет смысла. – fl00r

+0

Правда. Это не читаемо, но его можно разобрать, но Ruby делает это в определенных случаях. –

+0

@ fl00r Я попробовал следующее определение метода, и я получаю ту же ошибку. def hello (a, b = 1, c, d, e, * f) – Steve

ответ

5

Соответствующая документация here и вот связанный question. Они, кажется, не охватывают все случаи.

Здесь не то, что я мог собрать:

  • не может быть использован более чем один оператор восклицательный знак (*args).
  • Можно использовать несколько аргументов по умолчанию (a=1, b=2).
  • аргументы по умолчанию должны быть слева от оператора splat.
  • несколько аргументов по умолчанию должны поступать напрямую друг за другом.
  • Если используются аргументы по умолчанию и оператор splat, аргументы по умолчанию должны поступать прямо перед оператором splat.
  • Если выполняются приведенные выше правила, аргументы по умолчанию и оператор splat могут находиться в любом месте списка аргументов.

Для удобства чтения, это может быть хорошей идеей:

  • поставить оператор пейнтбольный как последний аргумент
  • избежать помещать аргументы по умолчанию в середине

Здесь действуют определения методов:

def hello(a = 1, b)   ;end 
def hello(a, b = 2)   ;end 
def hello(a = 1, b = 2)  ;end 
def hello(a = 1, b = 2, c)  ;end 
def hello(a, b = 2, c = 3)  ;end 
def hello(a, b = 2, *c)  ;end 
def hello(a, b = 2, *c, d)  ;end 
def hello(a = 1, b = 2, *c, d) ;end 

Для вашего второго примера, этот синтаксис будет хорошо:

def hello(a,b,c,d=1,*e,f) 
    p a,b,c,d,e,f 
end 

Для более полного примера с блоком и именованными аргументами см @ JörgWMittag отличных answer.

+0

Спасибо Эрик. Это тоже мое понимание. Я очень озадачен тем, что второй случай не работает для меня. – Steve

+0

@Steve В вашем втором примере, когда передано ровно 5 аргументов, неясно, следует ли передавать букву 'b' как« 1 »или ваш второй аргумент. Чтобы избежать этих двусмысленностей, Ruby применяет эти более строгие правила. –

+0

Спасибо @HolgerJust. Мой код не соответствует следующему правилу, о котором говорил Эрик. ** Если используются аргументы по умолчанию и оператор splat, аргументы по умолчанию должны поступать прямо перед оператором splat. ** Если я следую этому правилу, код работает нормально. – Steve