Ruby 2.0支持关键字参数.我想知道,将常规参数与关键字参数混合的"规则"是什么?这样的事情是行不通的:

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

但这将:

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

那么,为什么将常规参数放在关键字参数之前(而不是之后)有效呢?

网上有没有关于这个(混合关键字和常规参数)的参考资料?我好像找不到.

推荐答案

Ruby中参数列表的伪正则表达式(这同样适用于方法、块和lambda文本)如下所示:

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

下面是一个例子:

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> }

[注:Ruby 2.1中将引入强制关键字参数,其他所有参数都已生效.]

Ruby相关问答推荐

有没有办法保存 ruby​​ 代码的执行,以便稍后使用逐步重播对其进行调试?

安全导航运算符的使用是否应该在两种情况下进行单元测试(对象存在 + 对象无)?

如何在将拆分元素保留为空字符串的同时拆分字符串?

指南针手表:未定义的方法存在吗?对于文件:类

从整数中 Select 重复数字的字符串

环绕分隔线,保留第一列,最小最终长度

如何替换 ruby​​ 中模式的每个实例?

如果 Java 人go Scala,C# go F#,那么 Ruby 人go 哪里寻求函数式?

如何判断 Ruby 文件是否为空?

如何在Ruby中从字符串中go 除前导和尾随引号

Ruby 在与源相同的目录中加载配置(yaml)文件

如何使用 yardoc 列出未记录的模块/类/常量/方法?

在 jekyll 博客中支持标签的简单方法

在不同的换行符上拆分

. vs ::(点与双冒号)用于调用方法

如何在不使用循环的情况下按数组中的计数分组

计算文件中的行数而不将整个文件读入内存?

如何在 Ruby 中将类构造函数设为私有?

在类方法中使用实例变量 - Ruby

Ruby 哈希白名单过滤器