Ruby-混合命名和位置参数,为什么顺序很重要?

时间:2018-12-28 04:27:00

标签: ruby

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

// assuming jquery

$('.categoryCard').click(function(e){
   $('input[type="radio"]', this).each( function( i) {
     $(this).prop('checked', true);

   });

});

产生语法错误:

class Foo
  def initialize(bar:, bang:, bamph, &block)
    # ...
  end
end

这是

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

没有。

据我所知,this answer解释了参数类型的排序必须遵循特定的模式。但是通过执行此层次结构可以获得什么好处?

2 个答案:

答案 0 :(得分: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' })

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

open_file('test.txt', :mode => 'r', :encoding => 'UTF-8')

在Ruby 1.9中,引入了Hash文字的有限子集的另一种语法:当键是同时也是有效Ruby标识符的Symbol时(例如:foo,但是而不是:'foo-bar'),那么您可以这样写:

{ foo: bar }

代替

{ :foo => bar }

因此,我们可以像这样从上方调用方法:

open_file('test.txt', { mode: 'r', encoding: 'UTF-8' })

并且,由于省略括号的规则仍然适用,因此也是如此:

open_file('test.txt', mode: 'r', encoding: 'UTF-8')

这看起来很像其他语言中的关键字参数。实际上,具有Hash键的Symbol es的替代文字语法至少部分地专门设计用于提供将关键字参数和参数引入Ruby的过渡路径。

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

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

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

def open_file(name, mode: 'w', eol: :crlf, encoding:)
  # do your thing
end

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

open_file('test.txt', mode: 'r', encoding: 'UTF-8')

但是请注意,您不能再说这意味着什么!如果不查看方法的定义,就无法知道mode: 'r', encoding: 'UTF-8'Hash是文字还是两个关键字参数(换句话说,您甚至不知道这是一个还是两个参数!)在打电话。

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

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

  • 使用选项哈希定义并通过选项哈希调用的方法仍然必须工作。
  • 使用选项哈希定义并使用关键字参数调用的方法仍然必须工作。
  • 使用关键字参数定义并使用选项哈希文字调用的方法仍然必须工作。

为了使所有这些工作正常进行,哈希文字和关键字参数之间进行了许多隐式转换。如果只允许关键字参数和关键字参数出现在之前允许“ fake”关键字语法的位置(即,在参数列表的最后),则使此操作在没有麻烦的极端情况的情况下更容易实现 。和参数列表。

实际上,由于哈希和关键字参数之间的“模糊线条”,导致仍然出现了很多令人讨厌的极端情况。如果您查看Ruby问题跟踪器,您会发现自Ruby 2.0以来报告的大部分问题与这方面的不直观行为或纯粹的错误行为有关。每一个新版本都会带来新的变化,但每个人都会感觉到,他们修补的每个漏洞都会创建两个新漏洞。

现在,试想一下,如果规则不那么严格,会是什么样子!


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

答案 1 :(得分:0)

您可能必须在ruby-forums上挖掘才能找到权威的答案,但是我怀疑这样做是为了增强可读性,并且在调用该方法时可以忽略哈希周围的花括号。

考虑这样的方法:

def foo(num, hash, string); end

这是有效的调用:

foo(1, {a: :b}, "bar")

这不是,因为解析器不知道逗号是否分隔哈希键值或方法的参数:

foo(1, a: b, "bar")

当然,如果将哈希作为最后一个参数,则该方法将更加灵活,因为那样您就可以省略哈希周围的花括号。

您可以提出这样一个论点,即解析器应该能够知道最后一个逗号的含义,但是我不能告诉您这是多么困难,因为我不知道该语法的内部。 Ruby解析器。

如果像ES6 Javascript中那样具有更多功能齐全的结构化功能,那将是非常不错的选择,但是可惜我们没有(同样,这将给我带来很大的挑战,我无法告诉您)。我们所要做的就是以关键字params的形式进行基本的哈希分解。而且,关键字params必须排在最后的可能原因是,确保我们省略了哈希括号的语法糖可用。