什么是选项哈希?

Posted

技术标签:

【中文标题】什么是选项哈希?【英文标题】:What are options hashes? 【发布时间】:2013-08-26 18:54:20 【问题描述】:

有人能解释一下选项哈希吗?我正在学习 testfirst.org 的 ruby​​ 课程。练习 10 (temperature_object) 需要了解选项哈希。

【问题讨论】:

【参考方案1】:

选项散列是一个很好的概念,由 ruby​​ 解析器的一个特性启用。比如说,您有一个带有一些必需参数的方法。您也可以传递一些可选参数。随着时间的推移,您可能会添加更多可选参数或删除旧参数。为了保持方法声明的干净和稳定,您可以在哈希中传递所有这些可选参数。这种方法看起来像这样:

def foo(arg1, arg2, opts = )
  opts.to_s # just return a string value of opts
end

所以它有两个必需的值和最后一个参数,默认值为哈希。如果你没有任何可选参数要传递,你可以这样称呼它:

foo(1, 2) # => ""

如果你有一些可选的,你可以这样称呼它:

foo(1, 2, truncate: true, redirect_to: '/') # => ":truncate=>true, :redirect_to=>\"/\""

这段代码对 ruby​​ 来说是如此地道,以至于它的解析器实际上允许您在将哈希作为最后一个参数传递给方法时省略花括号:

foo(1, 2, truncate: true, redirect_to: '/') # => ":truncate=>true, :redirect_to=>\"/\""

例如,如果您使用 rails,您会看到选项散列无处不在。在这里,我在我的应用中只打开了一个随机控制器:

class ProductsController < ApplicationController
  before_filter :prepare_search_params, only: :index
                                    #    ^^^^^^^^^^ options hash here

因此,简而言之:options hash 是位于最后且默认值为 的方法的参数。你通常会向它传递哈希值(因此得名)。

【讨论】:

在现代版本的 Ruby 上,您应该真正使用关键字参数而不是选项哈希。 @JörgWMittag 你能解释一下吗? @Dennis:foo(arg1, arg2, truncate: false, redirect_to:)。请参阅this answer 了解整个故事。 @JörgWMittag 哦,原来我知道 - 这些术语让我很困惑,因为使用较新的语法在技术上仍然会给你一个“选项哈希”。无论如何,展示一个例子总是好的。【参考方案2】:

当需要将可选参数传递给方法时,会大量使用选项哈希。

例如,如果方法有一两个可选参数,你可以写

def method(arg1, arg2 = nil, arg3 = nil)
  ...
end

但是,如果您有更多可选参数,那么每次都将它们分配给 nil 会变得很难看。 这是允许您编写的选项哈希

def method(arg1, options=)
  @arg1 = arg1
  @arg2 = options[:arg2]
  ....
  @arg15 = options[:arg15]
end

【讨论】:

【参考方案3】:

选项哈希是指使用哈希 () 将选项传递给方法的约定,就像这样

my_func(arg1, arg2, :opt1 => 'foo', :opt2 => 'bar')

约定是将选项散列作为最后一个参数,以便可以将其设为可选。例如

def my_func(argument1, argument2, options = )
   ...
end

所以选项哈希没有什么特别的。它只是一个可选的最终参数,它是一个哈希。选项散列非常方便和常见,解释器还允许你去掉大括号(这是关于它们的一个“特殊”部分)

my_func(arg1, arg2, :opt1 => 'foo', :opt2 => 'bar')

结合 Ruby 的 Symbol 哈希键快捷键和可选的括号,这最终看起来非常干净:

my_func arg1, arg2, opt1: 'foo', opt2: 'bar'

【讨论】:

【参考方案4】:

由于所有这些答案都是正确的,ruby 2 改进了对关键字参数的支持。

您可以将默认哈希参数定义为*args,并去掉options =

def foo(bar: 'initial')
  puts bar
end

foo # => 'initial'
foo(bar: 'final') # => 'final'

必填参数:键后需要冒号(也需要 ruby​​ 2.1)

def foo(bar:)
  puts bar
end

foo # => ArgumentError: missing keyword: bar
foo(bar: 'baz') # => 'baz'   

可选参数,可以设置默认为nil

def foo(bar: nil, baz: 'aaa')
  puts "#bar:#baz"
end

foo # => ':aaa'
foo(baz: 'zab') # => ':zab'
foo(bar: 'rab', baz: 'zab') # => 'rab:zab'
foo(bin: 'bin') # => ArgumentError: unknown keyword: bin

您还可以将标准位置参数与这个新的散列参数表示法一起使用。您可以在blog 和oficial 文档中找到更多信息。

奖励:重构很容易,因为您可以在不更改方法调用的情况下删除方法的选项哈希。但是...这并不完全正确,如果您有一个带有意外选项的电话,您将收到一个ArgumentError: unknown keyword: invalid_arg

【讨论】:

【参考方案5】:

反向合并是在 ruby​​/rails 中实现选项哈希的最佳方式:

def set_state_application(options_hash)
  options_hash.reverse_merge!(send_email: true, other_default_val: 'a') #will set defaults
  self.update_column(:status_id, VendorEnums::VendorStatus::APPLICATION)
  VendorMailer.email_application(self) if options_hash[:send_email]
  save_state
end

【讨论】:

以上是关于什么是选项哈希?的主要内容,如果未能解决你的问题,请参考以下文章

将锚标记哈希到特定的导航选项卡

是否可以将助手嵌套在带有把手的选项哈希中?

JavaScript 选项哈希使用jQuery

使用jQuery的选项哈希

html 根据所选选项将哈希添加到URL

哈希值是啥意思?