Ruby 2中的命名参数

mwngjboj  于 2023-02-08  发布在  Ruby
关注(0)|答案(9)|浏览(189)

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

tktrz96b1#

我认为你的问题可以用明确的例子来解释。在下面的例子中,你有一个明确顺序的可选参数:

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'

虽然这两种方法在不提供参数的情况下是相似的,但当用户为方法提供参数时,它们就不同了。使用命名参数,调用者可以指定要提供哪个参数。特别是,最后一个示例(只提供地址)在第一个示例中不太容易实现;你可以只通过提供两个参数给方法来得到相似的结果。2这使得命名参数方法更加灵活。

35g0bw71

35g0bw712#

你发布的最后一个例子是误导性的。我不同意行为与前一个相似。最后一个例子将参数散列作为第一个可选参数传递进来,这是不同的事情!
如果不想使用默认值,可以使用nil
如果你想读一篇好的评论,请参阅“Ruby 2 Keyword Arguments“。

t0ybt7op

t0ybt7op3#

从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"
5hcedyr0

5hcedyr04#

我同意你的观点,使用命名参数需要默认值是很奇怪的,显然Ruby维护者也同意我们的观点!

4bbkushb

4bbkushb5#

这一点在所有其他答案中都存在,但我想提取出这一本质。
有四种参数:
| | 必需|可选|
| - ------|- ------|- ------|
| 位置|def PR(a)|def PO(a=1)|
| 关键词|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]
  • EDIT:所需的关键字参数(没有默认值)在Ruby 2.1.0中是新的,正如其他人提到的。*
6rqinv9w

6rqinv9w6#

把它留在这里是因为它帮了我很多。

示例

假设你有这样的:

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

而且很管用!

ykejflvf

ykejflvf7#

根据“Ruby 2.0.0 by Example“,您必须具有默认值:
在Ruby 2.0.0中,关键字参数必须有默认值,否则必须在末尾用**extra捕获。

whlutmcx

whlutmcx8#

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
jhdbpxl9

jhdbpxl99#

可以定义命名参数,如

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

如果您没有传递其中一个参数,Ruby将报告undefined local variable or method

相关问题