为啥不能在 Ruby 3 中结合 `...` 和命名参数?

Posted

技术标签:

【中文标题】为啥不能在 Ruby 3 中结合 `...` 和命名参数?【英文标题】:Why is it not possible to combine `...` and named arguments in Ruby 3?为什么不能在 Ruby 3 中结合 `...` 和命名参数? 【发布时间】:2021-08-21 10:29:57 【问题描述】:

在 Ruby 3 中,引入了新的 ... 语法,允许如下构造:

def locked_run(...)
  lock
  run(...)
  unlock
end

这在此处记录:https://rubyreferences.github.io/rubychanges/3.0.html

经过这次讨论 (https://bugs.ruby-lang.org/issues/16378),决定也加入位置参数:

  def block_section(name, ...)
    section(name, true, ...)
  end

但是,以下仍然会导致语法错误:

  def block_section(...)
    section(block_section: true, ...)
  end

为什么... 允许使用位置参数,但不允许使用命名参数?

【问题讨论】:

这不是完全您的问题的答案,但您能不能在这里指定**options 作为方法参数,并在下面指定**options.merge(block_section: true) 但是,如果您的方法也可能期望接收位置参数,这将不起作用。 在链接讨论中Matz也explains做出这个决定的原因,即支持sendmethod_missing 【参考方案1】:
section(block_section: true, ...)

这无论如何都不是正确的语法。看看 Ruby 是如何做事的,它期望命名参数(即哈希)是普通参数之后的最后一个参数。

def section(a,b,c,d: false)
  puts "#a #b #c #d"
end

def old_style_block_section(*args)
  section(*args,d: true)
  
  #=> syntax error, unexpected *, expecting ')'
  section(d: true,*args)
end

section(1,2,3,d: true)
old_style_block_section(1,2,3)

#=> syntax error, unexpected ',', expecting =>
section(d: true,1,2,3)

所以你需要的是这样的:

section(..., block_section: true)

但是,这仍然不起作用,因为它尚未作为新 ... 的 Ruby 语言语法的一部分实现。

如果你想要这个,我建议创建一个问题(或通过电子邮件或其他方式)来请求它。

【讨论】:

以上是关于为啥不能在 Ruby 3 中结合 `...` 和命名参数?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能在 Ruby 中将块传递给 proc?

为啥 Rails 不能与 mod_ruby 一起工作?

为啥 Kernel#require 在 Ruby 中引发 LoadError?

在 sklearn 和命名列中对多个列进行 One-hot-encoding

为啥在 Ruby 异常处理期间使用“确保”? [复制]

一个核糖体与mRNA的结合部位,为啥形成2个tRNA结合位点