之后有必需的参数而不是可选的参数

之后有必需的参数而不是可选的参数

本文介绍了为什么我可以在 Ruby 中的 splat 之后有必需的参数而不是可选的参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这在 Ruby 中是可能的:

This is possible in Ruby:

class SomeClass
  def initialize(a, *b, c)
  end
end

但这不是:

class SomeClass
  def initialize(a, *b, c='anything here')
  end
end

为什么?

这个问题没有答案.在链接的答案中,第一个答案是:

This question does NOT have an answer. In the answer linked, the first answer is:

splat 的意思是用完所有剩余的参数"但是你提供一个可选参数,那么解释器如何知道最后一个参数是数字"splat 或可选的一部分选项"?

这不是一个有效的答案,因为根据这个逻辑,Ruby 也不允许在 splat 之后使用强制参数.

Which is NOT a valid answer because according to this logic, Ruby would also not allow mandatory parameters after a splat.

推荐答案

Ruby 的参数绑定语义已经非常复杂.考虑这种方法:

Ruby's argument binding semantics are already pretty complex. Consider this method:

def foo(m1, m2, o1=:o1, o2=:o2, *splat, m3, m4,
          ok1: :ok1, mk1:, mk2:, ok2: :ok2, **ksplat, &blk)
  local_variables.map {|var| [var, eval(var.to_s)] }.to_h
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]]

你能一眼看出以下调用的结果吗?

Can you tell at first glance what the result of the following invocations will be?

foo(1, 2, 3, 4)

foo(1, 2, 3, mk1: 4, mk2: 5)

foo(1, 2, 3, 4, mk1: 5, mk2: 6)

foo(1, 2, 3, 4, 5, mk1: 6, mk2: 7)

foo(1, 2, 3, 4, 5, 6, mk1: 7, mk2: 8)

foo(1, 2, 3, 4, 5, 6, 7, mk1: 8, mk2: 9)

foo(1, 2, 3, 4, 5, 6, 7, 8, mk1: 9, mk2: 10)

foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11)

foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11, ok2: 12)

foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11, ok2: 12, k3: 13)

foo(1, 2, 3, 4, 5, 6, 7, 8, ok1: 9, mk1: 10, mk2: 11, ok2: 12, k3: 13, k4: 14)

foo(1, 2, 3, 4, 5, 6, 7, 8,
      ok1: 9, ok2: 10, mk1: 11, mk2: 12, k3: 13, k4: 14) do 15 end

现在,想象一下在 splat 参数之后将带有默认参数的可选参数添加到该列表中.为此找到合理的语义并非不可能,但可能会导致一些不明显的结果.

Now, imagine adding optional parameters with default arguments after the splat parameter to that list. It's not impossible to find sane semantics for that, but it may lead to some non-obvious results.

你能想出简单、理智、向后兼容且不令人惊讶的语义吗?

Can you come up with simple, sane, backwards-compatible, and non-surprising semantics?

顺便说一句:这是顶部方法的备忘单:

BTW: here's the cheatsheet for the method at the top:

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 中的 splat 之后有必需的参数而不是可选的参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-30 20:21