Ruby 2中的命名参数

时间:2013-03-09 06:54:49

标签: ruby ruby-2.0

我完全不了解Ruby 2.0中的命名参数是如何工作的。

def test(var1, var2, var3)
  puts "#{var1} #{var2} #{var3}"
end

test(var3:"var3-new", var1: 1111, var2: 2222) #wrong number of arguments (1 for 3) (ArgumentError)

它被视为哈希。而且非常有趣,因为在Ruby 2.0中使用命名参数我必须为它们设置默认值:

def test(var1: "var1", var2: "var2", var3: "var3")
  puts "#{var1} #{var2} #{var3}"
end

test(var3:"var3-new", var1: 1111, var2: 2222) # ok => 1111 2222 var3-new

与Ruby之前使用默认参数值的行为非常相似:

def test(var1="var1", var2="var2", var3="var3")
  puts "#{var1} #{var2} #{var3}"
end

test(var3:"var3-new", var1: 1111, var2: 2222) # ok but ... {:var3=>"var3-new", :var1=>1111, :var2=>2222} var2 var3

我知道为什么会这样,几乎是如何运作的。

但我只是好奇,必须如果我使用命名参数,我会使用参数的默认值吗?

并且,有人可以告诉我这两者之间有什么区别吗?

def test1(var1="default value123")
  #.......
end

def test1(var1:"default value123")
  #.......
end

9 个答案:

答案 0 :(得分:34)

我认为您的更新问题的答案可以通过明确的示例来解释。在下面的示例中,您有一个显式顺序的可选参数:

def show_name_and_address(name="Someone", address="Somewhere")
  puts "#{name}, #{address}"
end

show_name_and_address
#=> 'Someone, Somewhere'

show_name_and_address('Andy')
#=> 'Andy, Somewhere'

命名参数方法不同。它仍允许您提供默认值,但它允许调用者确定要提供的参数(如果有):

def show_name_and_address(name: "Someone", address: "Somewhere")
  puts "#{name}, #{address}"
end

show_name_and_address
#=> 'Someone, Somewhere'

show_name_and_address(name: 'Andy')
#=> 'Andy, Somewhere'

show_name_and_address(address: 'USA')
#=> 'Someone, USA'

虽然这两种方法在没有参数的情况下是相似的,但是当用户为方法提供参数时它们会有所不同。使用命名参数,调用者可以指定提供哪个参数。具体地说,在第一个例子中,最后一个例子(只提供地址)是不太可能实现的;只有通过向方法提供BOTH参数才能获得类似的结果。这使命名参数更加灵活。

答案 1 :(得分:16)

首先,您发布的最后一个示例具有误导性。我完全不同意这种行为与之前的行为类似。最后一个示例将参数hash in作为第一个可选参数传递,这是另一回事!

如果您不想使用默认值,可以使用nil

如果您想阅读好的文章,请参阅“Ruby 2 Keyword Arguments”。

答案 2 :(得分:13)

我同意你的看法,将默认值作为使用命名参数的价格是很奇怪的,显然Ruby维护者同意我们的意见! Ruby 2.1将drop the default value requirement as of 2.1.0-preview1

答案 3 :(得分:10)

Ruby 2.1.0开始,您不再需要为命名参数设置默认值。如果省略参数的默认值,则需要调用者提供它。

def concatenate(val1: 'default', val2:)
  "#{val1} #{val2}"
end

concatenate(val2: 'argument')
#=> "default argument"

concatenate(val1: 'change')
#=> ArgumentError: missing keyword: val2

假设:

def test1(var1="default value123")
  var1
end

def test2(var1:"default value123")
  var1
end

未传递参数时,他们的行为方式相同:

test1
#=> "default value123"

test2
#=> "default value123"

但是当一个论点被传递时,他们的表现会大不相同:

test1("something else")
#=> "something else"

test2("something else")
#=> ArgumentError: wrong number of arguments (1 for 0)


test1(var1: "something else")
#=> {:var1=>"something else"}

test2(var1: "something else")
#=> "something else"

答案 4 :(得分:5)

这在所有其他答案中都有,但我想提取这个本质。

有四种参数:

*

定义函数时,在关键字参数之前指定位置参数,在可选参数之前指定必需参数。

             Required     Optional
Positional | def PR(a)  | def PO(a=1) |
Keyword    | def KR(a:) | def KO(a:1) |

编辑:必需的关键字参数(没有默认值)是Ruby 2.1.0中的新参数,正如其他人所提到的那样。

答案 5 :(得分:2)

def test(a = 1, b: 2, c: 3)
  p [a,b,c]
end

test #=> [1,2,3]
test 10 #=> [10,2,3]
test c:30 #=> [1,2,30] <- this is where named parameters become handy. 

您可以定义参数的默认值和名称,然后如果您有基于哈希的“命名”参数但无需在方法中定义默认值,则可以按照调用它的方式调用方法。

如果使用哈希值,则在每个“命名参数”的方法中都需要这个。

b = options_hash[:b] || 2

如:

  def test(a = 1, options_hash)
    b = options_hash[:b] || 2
    c = options_hash[:c] || 3
    p [a,b,c]
  end

答案 6 :(得分:1)

根据“Ruby 2.0.0 by Example”,您必须有默认值:

  

在Ruby 2.0.0中,关键字参数必须具有默认值,否则必须在最后添加** extra。

答案 7 :(得分:0)

您可以定义命名参数,例如

def test(var1: var1, var2: var2, var3: var3)
  puts "#{var1} #{var2} #{var3}"
end

如果你没有传递其中一个参数,那么Ruby会抱怨undefined local variable or method

答案 8 :(得分:0)

把它留在这里是因为它对我帮助很大。

示例

假设你有这个:

def foo(thing, to_print)
  if to_print
    puts thing
  end
end


# this works
foo("hi", true)
# hi
# => nil

所以您尝试添加参数名称,如下所示:

foo(thing: "hi", to_print: true)
# foo(thing: "hi", to_print: true)
# ArgumentError: wrong number of arguments (given 1, expected 2)
# from (pry):42:in `foo'

但不幸的是它出错了。

解决方案

只需在每个参数的末尾添加一个 :

def foo2(thing:, to_print:)
  if to_print
    puts thing
  end
end


foo2(thing: "hi", to_print: true)
# hi
# => nil

它有效!