允许使用Ruby 1.9的哈希语法?

3

虽然我已经使用Ruby 1.9一段时间了,但我最近才发现新的哈希语法已经被支持:

settings = {
  host: "localhost",
  port: 5984
}

相较而言:

settings = {
  "host" => "localhost"
}

我喜欢它与JavaScript的对象表示法相似,看起来有点像JSON,所以我可能会转而在我的所有库中使用它,但我仍然希望支持其他用户和假定旧语法的自己的项目。

因此,这实际上归结为一个非常简单的问题,需要同时测试符号和字符串。有没有一种简单的方法将这两行代码合并成一行?

return true if settings["host"] and settings["db"]

return true if settings[:host] and settings[:db]

2
我应该注意 - 我知道符号和字符串有不同的原因,并且我在这两行代码中做的事情实际上非常不同,但是为了朝着新语法前进,我基本上假装它们都是一样的。 - Cera
1
只需期望用户始终使用符号作为键(正如Sean Hill所解释的那样)。 - Dominik Honnef
1
@dominikh,新语法甚至无法在Ruby 1.8上解析。以下是ree-1.8.7的内容:settings = { host: "localhost" } SyntaxError: compile error (irb):89: odd number list for Hash settings = { host: "localhost" } ^ (irb):89: syntax error, unexpected ':', expecting '}'我认为他混淆了两个不同的问题。1)字符串与符号键和2)Ruby的新哈希语法。 - Sean Hill
嗯,我想我误解了你问题的一部分,因为我认为它只涉及字符串与符号之间的区别。如果你想支持1.8.x用户,在你的代码中不要使用新的哈希语法(称为哈希火箭)。编辑:好吧,那是我混淆了两个不同的人 :) 我的两个评论仍然适用。 - Dominik Honnef
如果您尝试使用1.9之前的 "=>" 语法,rubocop语法检查器会抛出错误。使用 { key: value } 而不是 { :key => value } 可以使 rubocop 得到满足。 - emery
如何将此哈希映射转换为新语法:settings = { "long key" => "value" } - Ricardo
3个回答

5

即使在 Ruby < 1.9 版本中,您也可以使用符号作为键。例如:

# Ruby 1.8.7
settings = { :host => "localhost" }
puts settings[:host] #outputs localhost
settings.keys[0].class # => Symbol

在 Ruby 1.9 中,创建哈希表的方法发生了改变。它将键转换为符号,并消除了哈希箭头的需要。

# Ruby 1.9.2
settings = { host: "localhost" }
settings[:host] # => "localhost"
settings.keys[0].class # => Symbol

在这两种情况下,如果我尝试使用settings["name"]访问 settings[:name],我会得到一个空值。 Ruby 1.9只是允许一种新的创建哈希表的方式。回答你的问题,据我所知,如果要与Ruby 1.8向后兼容,就不能使用新的{key: value}语法。


我认为在 Ruby 1.8 中仅使用符号作为键并不总是正确的,即使这是传统做法。然而,随着新语法的出现,似乎总是正确的了。如果兼容性很重要,我想我会在我的哈希子类中重载 [] 运算符。 - Cera
4
通常,我不太喜欢绝对说法,但是考虑到符号在存储方面的优势,我会说最好使用符号。当你创建一个符号时,只会创建一个实例;而当你使用字符串时,每次都会创建一个新实例。你可以通过执行 10.times { puts "hello".object_id; puts :hello.object_id } 来观察此过程。每个字符串的 object_id 都会改变,但符号的 object_id 永远不会改变。 - Sean Hill

3

ActiveSupport(来自Rails)提供HashWithIndifferentAccess。您需要明确使用它,而不是标准哈希。

但请注意,这个类本身的一句话:

这个类的语义有问题,我们只是让人们可以编写params [:key]而不是params [‘key’],并且他们可以获得两个键的相同值。


那个引用从Rails 3开始已经消失了。另外,新网站是http://api.rubyonrails.org/。 - Kelvin

1
所以,这实际上归结为一个相当简单的问题,需要同时测试符号和字符串。有没有一种简单的方法将这两行代码合并成一行?
return true if settings["host"] and settings["db"]
return true if settings[:host] and settings[:db]

我不确定你到底在问什么,因为这似乎与原标题没有完全相关,但是可以试试:

# somewhere you get the values you are going to need to look up...
host = 'foo'
db = 'bar'
# then code goes by...
return true if settings[host.to_sym] and settings[db.to_sym]

# later you assign a symbol to one of the keys:
host = :foo
# more code goes by...
return true if settings[host.to_sym] and settings[db.to_sym]

这都是一样的。让 Ruby 根据需要从字符串转换为符号。

这个方法可行的原因是:

'foo'.to_s   # => "foo"
:foo.to_s    # => "foo"
'foo'.to_sym # => :foo
:foo.to_sym  # => :foo

你可以选择使用符号或字符串作为哈希键,让 Ruby 自行处理。


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