48

我不完全理解 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
4

9 回答 9

64

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

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'

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

于 2013-09-17T18:19:45.147 回答
23

您发布的最后一个示例具有误导性。我不同意这种行为与以前的行为相似。最后一个示例将参数散列作为第一个可选参数传入,这是另一回事!

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

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

于 2013-03-09T10:27:56.340 回答
14

我同意你的看法,要求默认值作为使用命名参数的代价是很奇怪的,显然 Ruby 维护者同意我们的观点!从 2.1.0-preview1 开始, Ruby 2.1 将放弃默认值要求。

于 2013-10-11T03:09:37.553 回答
14

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"
于 2015-05-30T04:08:15.473 回答
10

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

有四种参数:

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

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

irb(main):006:0> def argtest(a,b=2,c:,d:4)
irb(main):007:1> p [a,b,c,d]
irb(main):008:1> end
=> :argtest

irb(main):009:0> argtest(1,c: 3)
=> [1, 2, 3, 4]

irb(main):010:0> argtest(1,20,c: 3,d: 40)
=> [1, 20, 3, 40]

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

于 2016-09-10T21:10:59.357 回答
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
于 2013-07-12T18:35:39.830 回答
2

根据“示例 Ruby 2.0.0 ”,您必须具有默认值:

在 Ruby 2.0.0 中,关键字参数必须具有默认值,否则必须在末尾被 **extra 捕获。

于 2013-03-09T10:57:50.267 回答
1

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

例子

假设你有这个:

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

它有效!

于 2021-02-16T11:46:14.413 回答
0

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

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

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

于 2013-07-08T08:53:55.663 回答