Ruby - 混合名称和位置参数,为什么订单很重要?

011*_*112 1 ruby

使用命名和位置参数创建函数

class Foo
  def initialize(bar:, bang:, bamph, &block)
    # ...
  end
end
Run Code Online (Sandbox Code Playgroud)

产生语法错误:

$ ruby -c scratch.rb
scratch.rb:2: syntax error, unexpected tIDENTIFIER
...f initialize(bar:, bang:, bamph, &block)
...                          ^~~~~
Run Code Online (Sandbox Code Playgroud)

这个

 def initialize(bamph, bar:, bang:,  &block)
    # ...
 end
Run Code Online (Sandbox Code Playgroud)

才不是.

据我所知,这个答案解释了参数类型的顺序必须遵循特定的模式.但是通过强制执行此层次结构可以获得什么好处?

Jör*_*tag 7

关键字参数和参数在Ruby中相对较新.它们仅在Ruby 2.0中引入.

在Ruby有关键字参数和参数之前,有一种广泛使用的习惯用法,即将Hash文字作为方法的最后一个参数传递.这个成语看起来像这样:

DEFAULTS = {
  :mode => 'w',
  :eol => :crlf,
}

def open_file(name, options = {})
  raise ArgumentError unless options[:encoding]
  options = DEFAULTS.merge(option)
  mode, eol, encoding = options[:mode], options[:eol], options[:encoding]
  # do your thing
end

open_file('test.txt', { :mode => 'r', :encoding => 'UTF-8' })
Run Code Online (Sandbox Code Playgroud)

为了使它看起来更像"类似关键字",如果你传递一个Hash文字作为消息发送的最后一个参数,你可以省略括号:

open_file('test.txt', :mode => 'r', :encoding => 'UTF-8')
Run Code Online (Sandbox Code Playgroud)

在Ruby 1.9中,Hash引入了有限文字子集的替代语法:当密钥是Symbol一个有效的Ruby标识符(例如:foo但不是:'foo-bar')时,您可以这样写:

{ foo: bar }
Run Code Online (Sandbox Code Playgroud)

代替

{ :foo => bar }
Run Code Online (Sandbox Code Playgroud)

所以,我们可以像这样从上面调用我们的方法:

open_file('test.txt', { mode: 'r', encoding: 'UTF-8' })
Run Code Online (Sandbox Code Playgroud)

因为关于遗漏括号的规则仍然适用,也是这样的:

open_file('test.txt', mode: 'r', encoding: 'UTF-8')
Run Code Online (Sandbox Code Playgroud)

这看起来非常像其他语言中的关键字参数.事实上,HashSymbol密钥的es的这种替代文字语法至少部分专门设计用于提供将关键字参数和参数引入Ruby的过渡路径.

在Ruby 2.0中,引入了带有默认关键字参数的可选关键字参数:

def open_file(name, mode: 'w', eol: :crlf, encoding: nil)
  raise ArgumentError unless encoding
  # do your thing
end
Run Code Online (Sandbox Code Playgroud)

然后在Ruby 2.1强制关键字参数和参数中:

def open_file(name, mode: 'w', eol: :crlf, encoding:)
  # do your thing
end
Run Code Online (Sandbox Code Playgroud)

您可能知道,调用此方法看起来与以前完全一样:

open_file('test.txt', mode: 'r', encoding: 'UTF-8')
Run Code Online (Sandbox Code Playgroud)

但请注意,您无法再说出这意味着什么!您无法知道是否mode: 'r', encoding: 'UTF-8'Hash文字或两个关键字参数(换句话说,您甚至不知道这是一个还是两个参数!)而不会查看您调用的方法的定义.

决定Ruby 2.0应该最大程度地向前和向后兼容Ruby 1.9.

因此,以下所有必须为真:

  • 使用选项哈希定义并使用选项哈希调用的方法必须仍然有效.
  • 使用选项哈希定义并使用关键字参数调用的方法必须仍然有效.
  • 使用关键字参数定义并使用选项哈希文字调用的方法必须仍然有效.

为了完成所有这些工作,散列文字和关键字参数之间存在大量隐式转换.如果只允许关键字参数和关键字参数出现在之前允许使用"假"关键字语法的位置,即参数列表和参数列表的最后,那么在没有讨厌的极端情况下使其工作更容易.

其实,有仍然引起这个有很多的肮脏角落案件"界限模糊"散列关键字和参数之间.如果您查看Ruby问题跟踪器,您会发现自Ruby 2.0以来报告的很大一部分问题与这方面的非直观或简单的错误行为有关.每一个新版本都会带来新的变化,但是人们会感觉到,对于他们修补的每一个洞,他们创造了两个新的洞.

现在,想象一下如果规则更严格的话会是什么样的!


以下是上述问题的一些例子: