为什么双splat只能使用符号键?

时间:2014-08-07 20:38:05

标签: ruby hash key symbols

双splat运算符**似乎只适用于其键为符号的哈希。例如,当键是字符串时,它将不起作用。这两种方式都是如此;施工:

def foo **; end
foo(:a => 3) #=> nil
foo("a" => 3) #=> ArgumentError: wrong number of arguments (1 for 0)

和破坏:

def bar *; end
bar(**{:a => 3}) #=> nil
bar(**{"a" => 3}) #=> TypeError: wrong argument type String (expected Symbol)

为什么它仅限于符号键?

这可能与命名关键字符号a: 3与带符号键的哈希的语法糖一致,但如上所示,双splat与普通哈希符号:a => 3一起使用,所以我不确定这一点。

2 个答案:

答案 0 :(得分:6)

我最近碰到了这样的事情。

如果你在Rails中并且你有一个方法接受关键字参数并且你有一个强大的params哈希要发送给它,你可以在params哈希上使用symbolize_keys它会正确地分离出论点,不需要双重splat。

模型

class ContactForm
  def initialize(name:, email:)
    @name = name
    @email = email
  end
  # Other stuff
end

控制器

class ContactController < ApplicationController
  def send_mail
    @contact_form = ContactForm.new(contact_params)
    if @contact_form.submit
      # Do stuff
    end
  end

  def contact_params
    params.require(:contact_form).permit(:name, :email).symbolize_keys
  end
end

答案 1 :(得分:5)

简短的回答:关于double-splat运算符应该捕获的关键字参数如何用Ruby表示。

答案很长:双重splat运算符用于捕获关键字,如以下答案所示:https://stackoverflow.com/a/18289218/3644699

从Ruby 2.0开始,Ruby支持真正的关键字参数。我的猜测是,在主要实现中,它们仍然表示为Hashes,其键是符号,类似于在语言正式支持它们之前模拟它们的方式。

您可能遇到的特定错误可能取决于实施情况。例如,在irb中执行后一个代码片段会显示引发TypeError的函数:

2.1.2 :001 > def bar *; end
 => :bar 
2.1.2 :002 > bar(**{"a" => 3})
TypeError: wrong argument type String (expected Symbol)
    from (irb):2:in `core#hash_merge_kwd'
    from (irb):2
    from /home/mkis/.rvm/rubies/ruby-2.1.2/bin/irb:11:in `<main>'
2.1.2 :003 > 

hash_merge_kwd是一个内部函数,在此处定义:https://github.com/ruby/ruby/blob/d738e3e15533e0f500789faaedcef9ed9ca362b9/vm.c#L2398