什么是选项哈希?

33

有人可以解释一下选项哈希(options hashes)吗?我正在从testfirst.org的Ruby课程中学习。练习10(temperature_object)需要了解选项哈希的知识。

5个回答

59

选项哈希是由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 中非常典型,实际上,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

简而言之:选项哈希表是一个位于最后且默认值为{}的方法参数。通常你会将哈希表传递给它(因此得名“哈希”)。


8
在现代版本的Ruby中,你应该使用关键字参数而不是选项哈希表。 - Jörg W Mittag
@JörgWMittag 你能解释一下吗? - Dennis
1
@Dennis: foo(arg1, arg2, truncate: false, redirect_to:). 查看此答案了解完整情况。 - Jörg W Mittag
@JörgWMittag 哦,原来我知道这个 - 术语让我感到困惑,因为使用较新的语法仍然会给你一个“选项哈希”。无论如何,展示一个例子总是很好的。 - Dennis

13

当需要向方法传递可选参数时,选项哈希经常被使用。

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


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

但是如果你有更多的可选参数,每次将它们赋值为nil就变得很丑陋。

这时候可以使用选项哈希,让你可以编写:

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

7
一个选项哈希指的是使用哈希({})将选项传递给方法的惯例,例如:
my_func(arg1, arg2, {:opt1 => 'foo', :opt2 => 'bar'})

惯例上,选项哈希应该是最后一个参数,这样可以使其变成可选项。例如:

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

因此,选项哈希并不是什么特别的东西。它只是一个可选的最后一个参数,是一个哈希。选项哈希非常方便和常见,解释器还允许您省略大括号(这是它们的一个“特殊”之处)。
my_func(arg1, arg2, :opt1 => 'foo', :opt2 => 'bar')

结合 Ruby 的符号哈希键快捷方式和可选括号,这样可以使代码看起来非常简洁:
my_func arg1, arg2, opt1: 'foo', opt2: 'bar'

7
由于这些答案都是正确的,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

此外,您还可以使用新的哈希参数符号与标准位置参数一起使用。您可以在此博客官方文档中找到更多信息。
额外福利:重构很容易,因为您可以在不更改调用方法的情况下清除方法中的选项哈希。但是......这并不完全正确,如果您有一个带有意外选项的调用,则会收到ArgumentError: unknown keyword: invalid_arg错误。

4

逆向合并是在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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接