class Hash

Hash 对象将每个唯一的键映射到一个特定的值。

哈希在某些方面与 Array 相似,但

Hash 数据语法

哈希条目的原始语法使用“哈希火箭” =>

h = {:foo => 0, :bar => 1, :baz => 2}
h # => {foo: 0, bar: 1, baz: 2}

或者,但仅适用于符号键,您可以使用较新的 JSON 风格语法,其中每个裸词都变成一个符号

h = {foo: 0, bar: 1, baz: 2}
h # => {foo: 0, bar: 1, baz: 2}

您也可以在字符串中使用裸词

h = {'foo': 0, 'bar': 1, 'baz': 2}
h # => {foo: 0, bar: 1, baz: 2}

您还可以混合使用样式

h = {foo: 0, :bar => 1, 'baz': 2}
h # => {foo: 0, bar: 1, baz: 2}

但是,对于非裸词或字符串键尝试 JSON 风格语法会导致错误

# Raises SyntaxError (syntax error, unexpected ':', expecting =>):
h = {0: 'zero'}

值可以省略,这意味着将通过键的名称从上下文中获取该值

x = 0
y = 100
h = {x:, y:}
h # => {x: 0, y: 100}

常见用法

您可以使用哈希为对象命名

person = {name: 'Matz', language: 'Ruby'}
person # => {name: "Matz", language: "Ruby"}

您可以使用哈希为方法参数命名

def some_method(hash)
  p hash
end
some_method({foo: 0, bar: 1, baz: 2}) # => {foo: 0, bar: 1, baz: 2}

注意:当方法调用中的最后一个参数是哈希时,可以省略花括号

some_method(foo: 0, bar: 1, baz: 2) # => {foo: 0, bar: 1, baz: 2}

您可以使用哈希初始化对象

class Dev
  attr_accessor :name, :language
  def initialize(hash)
    self.name = hash[:name]
    self.language = hash[:language]
  end
end
matz = Dev.new(name: 'Matz', language: 'Ruby')
matz # => #<Dev: @name="Matz", @language="Ruby">

创建 Hash

您可以使用以下方式显式创建 Hash 对象:

您可以使用以下方法将某些对象转换为哈希:

您可以通过调用方法 Hash.new 来创建一个哈希

# Create an empty hash.
h = Hash.new
h # => {}
h.class # => Hash

您可以通过调用方法 Hash.[] 来创建一个哈希

# Create an empty hash.
h = Hash[]
h # => {}
# Create a hash with initial entries.
h = Hash[foo: 0, bar: 1, baz: 2]
h # => {foo: 0, bar: 1, baz: 2}

您可以使用其字面量形式(花括号)创建哈希

# Create an empty hash.
h = {}
h # => {}
# Create a +Hash+ with initial entries.
h = {foo: 0, bar: 1, baz: 2}
h # => {foo: 0, bar: 1, baz: 2}

Hash 值基础

检索哈希值(实例方法 [])的最简单方法

h = {foo: 0, bar: 1, baz: 2}
h[:foo] # => 0

创建或更新哈希值(实例方法 []=)的最简单方法

h = {foo: 0, bar: 1, baz: 2}
h[:bat] = 3 # => 3
h # => {foo: 0, bar: 1, baz: 2, bat: 3}
h[:foo] = 4 # => 4
h # => {foo: 4, bar: 1, baz: 2, bat: 3}

删除哈希条目(实例方法 delete)的最简单方法

h = {foo: 0, bar: 1, baz: 2}
h.delete(:bar) # => 1
h # => {foo: 0, baz: 2}

条目顺序

Hash 对象按创建顺序显示其条目。这在以下情况中可见:

新哈希根据给定条目具有初始顺序

h = Hash[foo: 0, bar: 1]
h # => {foo: 0, bar: 1}

新条目添加到末尾

h[:baz] = 2
h # => {foo: 0, bar: 1, baz: 2}

更新值不会影响顺序

h[:baz] = 3
h # => {foo: 0, bar: 1, baz: 3}

但重新创建已删除的条目会影响顺序

h.delete(:foo)
h[:foo] = 5
h # => {bar: 1, baz: 3, foo: 5}

Hash

Hash 键等价性

当两个对象的 hash 值相同且两个对象彼此 eql? 时,它们被视为相同的哈希键。

修改活动Hash

在活动 Hash 中修改键会损坏哈希的索引。

Hash 的键是数组

a0 = [ :foo, :bar ]
a1 = [ :baz, :bat ]
h = {a0 => 0, a1 => 1}
h.include?(a0) # => true
h[a0] # => 0
a0.hash # => 110002110

修改数组元素 a0[0] 会更改其哈希值

a0[0] = :bam
a0.hash # => 1069447059

并损坏 Hash 索引

h.include?(a0) # => false
h[a0] # => nil

您可以使用 rehash 方法修复哈希索引

h.rehash # => {[:bam, :bar]=>0, [:baz, :bat]=>1}
h.include?(a0) # => true
h[a0] # => 0

字符串键始终是安全的。这是因为作为键传递的未冻结字符串将被复制和冻结的字符串替换

s = 'foo'
s.frozen? # => false
h = {s => 0}
first_key = h.keys.first
first_key.frozen? # => true

用户定义的Hash

要用作 Hash 键,对象必须实现 hasheql? 方法。注意:如果 Hash 使用 compare_by_identity,则此要求不适用,因为比较将依赖于键的对象 ID 而不是 hasheql?

Objecthasheq? 定义了基本实现,使每个对象成为一个不同的键。通常,用户定义的类会覆盖这些方法以提供有意义的行为,或者继承 Struct,它具有这些方法的有用定义。

hash 的典型实现基于对象的 data,而 eql? 通常别名为重写的 == 方法

class Book
  attr_reader :author, :title

  def initialize(author, title)
    @author = author
    @title = title
  end

  def ==(other)
    self.class === other &&
      other.author == @author &&
      other.title == @title
  end

  alias eql? ==

  def hash
    [self.class, @author, @title].hash
  end
end

book1 = Book.new 'matz', 'Ruby in a Nutshell'
book2 = Book.new 'matz', 'Ruby in a Nutshell'

reviews = {}

reviews[book1] = 'Great reference!'
reviews[book2] = 'Nice and compact!'

reviews.length #=> 1

键未找到?

当一个方法尝试检索并返回一个键的值,并且该键被找到时,返回的值是与该键关联的值。

但是,如果键未找到怎么办?在这种情况下,某些方法将返回默认值,而其他方法将引发 KeyError

Nil 返回值

如果您希望在找不到键时返回 nil,您可以调用

您可以覆盖 []digvalues_at(但不能覆盖 assoc)的这些行为;请参阅 Hash 默认值

KeyError

如果您希望在找不到键时引发 KeyError,您可以调用

Hash 默认值

对于某些方法([]digvalues_at),找不到键的返回值由两个哈希属性决定:

在简单情况下,两者都为 nil,并且这些方法在找不到键时返回 nil;请参阅上面的 Nil 返回值

请注意,本节(“Hash 默认值”)

任何键的默认值

您可以为哈希定义一个任何键的默认值,即一个将为任何未找到的键返回的值

您可以在创建哈希时使用 Hash.new 和选项 default_value 来设置默认值,或者稍后使用方法 default=

注意:虽然 default 的值可以是任何对象,但使用可变对象可能不是个好主意。

每个键的默认值

您可以为哈希定义一个每个键的默认值,即一个 Proc,它将根据键本身返回一个值。

您可以在创建哈希时使用 Hash.new 和块来设置默认 proc,或者稍后使用方法 default_proc=

请注意,proc 可以修改 self,但以这种方式修改 self 不是线程安全的;多个线程可以并发地为同一个键调用默认 proc。

方法默认值

对于两个方法,您可以为找不到的键指定一个默认值,该默认值仅在单次方法调用中生效(而不是在后续调用中生效)

这里有什么

首先,其他地方。类 Hash

此处,类 Hash 提供了有用的方法,用于

Hash 还包括来自模块 Enumerable 的方法。

创建 Hash 的方法

设置 Hash 状态的方法

查询方法

比较方法

获取元素的方法

赋值方法

删除方法

这些方法从 self 中移除条目

这些方法返回 self 的副本,其中包含一些已移除的条目

迭代方法

转换方法

转换键和值的方法