简体   繁体   English

在Ruby中将关键字与常规参数混合?

[英]Mixing keyword with regular arguments in Ruby?

Ruby 2.0 supports keyword arguments. Ruby 2.0支持关键字参数。 I was wondering, what are the 'rules' for mixing regular with keyword arguments? 我想知道,将常规与关键字参数混合的“规则”是什么? Something like this would not work: 这样的事情是行不通的:

def some_method(a: 'first', b: 'second', c)
  [a, b, c]
end

but this will: 但这将:

def some_method(c, a: 'first', b: 'second')
  [a, b, c]
end

So why does putting a regular argument before the keyword arguments (and not after) works? 那么,为什么在关键字参数之前(而不是之后)放置常规参数呢?

Is there some reference on the web on this (mixing keyword and regular arguments)? 网络上是否有一些参考(混合关键字和常规参数)? I can't seem to find any. 我似乎找不到任何东西。

The order is as follows: 顺序如下:

  • required arguments 必选参数
  • arguments with default values ( arg=default_value notation) 具有默认值的参数( arg=default_value表示法)
  • optional arguments ( *args notation, sometimes called "splat parameter") 可选参数( *args表示法,有时称为“ splat参数”)
  • required arguments, again 再次需要参数
  • keyword arguments 关键字参数
    • optional ( arg:default_value notation, since 2.0.0) 可选( arg:default_value表示法,从2.0.0开始)
    • intermixed with required ( arg: notation, since 2.1.0) 与required混合( arg:表示法,自2.1.0起)
  • arbitrary keyword arguments ( **args notation, since 2.0.0) 任意关键字参数( **args表示法,自2.0.0开始)
  • block argument ( &blk notation) 块参数( &blk表示法)

For example: 例如:

def test(a, b=0, *c, d, e:1, f:, **g, &blk)
  puts "a = #{a}"
  puts "b = #{b}"
  puts "c = #{c}"
  puts "d = #{d}"
  puts "e = #{e}"
  puts "f = #{f}"
  puts "g = #{g}"
  puts "blk = #{blk}"
end

test(1, 2, 3, 4, 5, e:6, f:7, foo:'bar') { puts 'foo' }
# a = 1
# b = 2
# c = [3, 4]
# d = 5
# e = 6
# f = 7
# g = {:foo=>"bar"}
# blk = #<Proc:0x007fb818ba3808@(irb):24>

More detailed information is available from the official Ruby Syntax Documentation . 可以从官方的Ruby语法文档中获得更多详细信息。

A pseudo-regex for parameter lists in Ruby (this applies equally to methods, blocks and lambda literals) is something like this: Ruby中参数列表的伪正则表达式(这同样适用于方法,块和lambda文字)如下所示:

mand* opt* splat? mand* (mand_kw | opt_kw)* ksplat? block?

Here's an example: 这是一个例子:

def foo(m1, m2, o1=:o1, o2=:o2, *splat, m3, m4, 
          ok1: :ok1, mk1:, mk2:, ok2: :ok2, **ksplat, &blk)
  Hash[local_variables.map {|var| [var, eval(var.to_s)] }]
end

method(:foo).arity
# => -5

method(:foo).parameters
# => [[:req, :m1], [:req, :m2], [:opt, :o1], [:opt, :o2], [:rest, :splat], 
#     [:req, :m3], [:req, :m4], [:keyreq, :mk1], [:keyreq, :mk2], 
#     [:key, :ok1], [:key, :ok2], [:keyrest, :ksplat], [:block, :blk]]

foo(1, 2, 3, 4)
# ArgumentError: missing keywords: mk1, mk2

foo(1, 2, 3, mk1: 4, mk2: 5)
# ArgumentError: wrong number of arguments (3 for 4+)

foo(1, 2, 3, 4, mk1: 5, mk2: 6)
# => { m1: 1, m2: 2, o1: :o1, o2: :o2, splat: [], m3: 3, m4: 4, 
#      ok1: :ok1, mk1: 5, mk2: 6, ok2: :ok2, ksplat: {}, 
#      blk: nil }

foo(1, 2, 3, 4, 5, mk1: 6, mk2: 7)
# => { m1: 1, m2: 2, o1: 3, o2: :o2, splat: [], m3: 4, m4: 5, 
#      ok1: :ok1, mk1: 6, mk2: 7, ok2: :ok2, ksplat: {}, 
#      blk: nil }

foo(1, 2, 3, 4, 5, 6, mk1: 7, mk2: 8)
# => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [], m3: 5, m4: 6, 
#      ok1: :ok1, mk1: 7, mk2: 8, ok2: :ok2, ksplat: {}, 
#      blk: nil }

foo(1, 2, 3, 4, 5, 6, 7, mk1: 8, mk2: 9)
# => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5], m3: 6, m4: 7, 
#      ok1: :ok1, mk1: 8, mk2: 9, ok2: :ok2, ksplat: {}, 
#      blk: nil }

foo(1, 2, 3, 4, 5, 6, 7, 8, mk1: 9, mk2: 10)
# => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
#      ok1: :ok1, mk1: 9, mk2: 10, ok2: :ok2, ksplat: {}, 
#      blk: nil }

foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11)
# => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
#      ok1: 9, mk1: 10, mk2: 11, ok2: :ok2, ksplat: {}, 
#      blk: nil }

foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11, ok2: 12)
# => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
#      ok1: 9, mk1: 10, mk2: 11, ok2: 12, ksplat: {}, 
#      blk: nil }

foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11, ok2: 12, k3: 13)
# => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
#      ok1: 9, mk1: 10, mk2: 11, ok2: 12, ksplat: {k3: 13}, 
#      blk: nil }

foo(1, 2, 3, 4, 5, 6, 7, 8, 
      ok1: 9, mk1: 10, mk2: 11, ok2: 12, k3: 13, k4: 14)
# => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
#      ok1: 9, mk1: 10, mk2: 11, ok2: 12, ksplat: {k3: 13, k4: 14}, 
#      blk: nil }

foo(1, 2, 3, 4, 5, 6, 7, 8, 
      ok1: 9, ok2: 10, mk1: 11, mk2: 12, k3: 13, k4: 14) do 15 end
# => { m1: 1, m2: 2, o1: 3, o2: 4, splat: [5, 6], m3: 7, m4: 8, 
#      ok1: 9, mk1: 10, mk2: 11, ok2: 12, ksplat: {k3: 13, k4: 14}, 
#      blk: #<Proc:0xdeadbeefc00l42@(irb):15> }

[Note: mandatory keyword arguments will be introduced in Ruby 2.1, all the rest already works.] [注意:必填关键字参数将在Ruby 2.1中引入,其余所有参数都已经可用。]

  1. Arguments with defaults and splat argument must be grouped together; 带有默认值的参数和splat参数必须组合在一起。
  2. Splat argument must appear after positional arguments with default values but before keyword arguments; Splat参数必须出现在具有默认值的位置参数之后,但在关键字参数之前;
  3. Keyword arguments must appear after positional arguments and before double splat argument; 关键字参数必须出现在位置参数之后和double splat参数之前;
  4. Double splat argument must appear last but before block argument. 双splat参数必须出现在最后但在块参数之前。

    def foo(a, b=1, c=2, *d, e, f: 1, g: 2, **kwargs, &block) def foo(a,b = 1,c = 2,* d,e,f:1,g:2,** kwargs,&block)

Keyword arguments is just an optional hash argument, as I know. 据我所知,关键字参数只是一个可选的哈希参数。

def some_method(c, a: 'first', b: 'second')

is same as 与...相同

def some_method(c, { a: 'first', b: 'second' }) // will not compile actually

Ruby just interprets last arguments with hash syntax as hash. Ruby只是将使用哈希语法的最后一个参数解释为哈希。 So the first example doesn't work because ruby can't understand such syntax (has syntax at first place). 因此第一个示例不起作用,因为ruby无法理解这样的语法(首先是语法)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM