Когда Ruby встречает
def m(a=1, b=2, c=3)
puts "a=#{a}, b=#{b}, c=#{3}"
end
Вот что происходит:
m(4,5)
# a=4, b=5, c=3
У Руби нет способа узнать, какую переменную вы хотите назначить для ее значения по умолчанию, поэтому она применяет простое правило: присваивает аргументы переменным слева направо до тех пор, пока они не будут использованы, а все остальные аргументы присваиваются их значениям по умолчанию.
Если вы хотите другой приоритет, вы можете изменить порядок аргументов, скажем,
def m(b=2, c=3, a=1)
puts "a=#{a}, b=#{b}, c=#{3}"
end
m(4,5)
# a=1, b=4, c=3
В некоторых ситуациях этого может быть достаточно, но более гибкое решение, которое также лучше читается, заключается в использовании именованных аргументов (он же именованных параметров ), как это сделал @steenstag в своем решение. Здесь это может быть следующим.
def m(a: 1, b: 2, c: 3)
d = a + c
puts "a=#{a}, b=#{b}, c=#{c}, d=#{d}"
end
m(:b=>4, :c=>5)
# a=1, b=4, c=5, d=6
m(c: 4)
# a=1, b=2, c=4, d=5
Обратите внимание, что я написал c=>5
в первом случае и c: 4
во втором. Любая форма может быть использована. Мы не можем, однако, написать def m(:a=>1, :b=>2, :c=>3)
.
Начиная с Ruby v2.1, мы также можем иметь обязательных именованных аргументов:
def m(a:, b: 2, c: 3)
puts "a=#{a}, b=#{b}, c=#{c}"
end
m(c:5, a: 4)
# a=4, b=2, c=5
m(c: 5)
# ArgumentError (missing keyword: a)
У нас также могут быть некоторые именованные и некоторые безымянные аргументы, при условии, что именованные аргументы находятся в конце, но не так сложно просто назвать все аргументы, если они есть.
def m(d, a:, b: 2, c: 3)
puts "d=#{d}, a=#{a}, b=#{b}, c=#{c}"
end
m(6, c:5, a: 4)
# d=6, a=4, b=2, c=5
def m(a:, b: 2, c: 3, d)
end
#=> SyntaxError ((irb):165: syntax error, unexpected tIDENTIFIER)
# ... def m(a:, b: 2, c: 3, d)
# ^