发布于2026-06-29 阅读(0)
扫一扫,手机访问
提到 Ruby 中的 Hash,很多人第一反应就是“键值对集合”。确实,它和数组一样是 Ruby 里最常用的数据结构之一,但使用起来远比你想象的灵活——键可以是任意对象,值也能随意嵌套。下面我们就从最基础的创建开始,手把手把 Hash 的常用操作理一遍。
创建 Hash 实例和创建数组一样直观。通过 Hash.new 可以快速生成一个空的哈希,你还可以给它指定一个默认值——当访问不存在的键时,就会返回这个默认值:

h1 = Hash.new # 默认值为 nil
h2 = Hash.new("This is my first hash instance") # 默认值为 "This is my first hash instance"
有了哈希对象之后,添加或删除条目就跟数组一样简单。唯一不同的是,数组的索引只能是整数,而哈希的键(key)可以是任何类型的对象(且必须唯一):
h2["one"] = "北京"
h2["two"] = "上海"
h2["three"] = "深圳"
h2["four"] = "广州"
注意:如果赋值时用了已存在的键,后面的值会覆盖前面的。Ruby 还提供了一种更紧凑的创建和初始化方式——用 => 连接键值对,整体用大括号括起来:
h2 = {
"one" => "北京",
"two" => "上海",
"three" => "深圳",
"four" => "广州"
}
获取值的方法很直接:
puts h2["one"] # => "北京"
如果键不存在,就会返回之前设置的默认值。另外,使用 default 方法可以获取当前默认值,用 default= 可以重新设置:
puts h1.default
h1.default = "This is set value method"
和数组一样,直接把一个哈希变量赋给另一个变量,它们会指向同一个对象——修改其中一个,另一个也会跟着变:
h3 = h2
h3["one"] = "西安"
puts h2["one"] # => "西安"
如果你不想共享引用,可以用 clone 方法创建一个全新的副本:
h4 = h2.clone
h4["one"] = "大连"
puts h2["one"] # => "西安"(不受影响)
哈希排序不能像数组那样直接用 sort,因为数组里所有元素类型一致(整数),而哈希的键可能是整数、字符串等混合类型。需要自己处理一下:
def sorted_hash(aHash)
return aHash.sort{ |a,b| a.to_s <=> b.to_s }
end
h1 = {1=>'one', 2=>'two', 3=> 'three'}
h2 = {6=>'six', 5=>'five', 4=> 'four'}
h3 = {'one'=>'A', 'two'=>'B','three'=>'C'}
h4 = h1.merge(h2) # 合并 hash
h5 = h1.merge(h3)
p(h4)
p(h4.sort)
p(h5)
p(sorted_hash(h5))
结果如下:
{5=>"five", 6=>"six", 1=>"one", 2=>"two", 3=>"three", 4=>"four"}
[[1, "one"], [2, "two"], [3, "three"], [4, "four"], [5, "five"], [6, "six"]]
{"two"=>"B", "three"=>"C", 1=>"one", 2=>"two", "one"=>"A", 3=>"three"}
[[1, "one"], [2, "two"], [3, "three"], ["one", "A"], ["three", "C"], ["two", "B"]]
实际上,Hash 的 sort 方法内部会把哈希转换成以 [key, value] 为元素的数组,然后再用数组的排序逻辑进行排序。
| 方法 | 说明 |
|---|---|
size() |
返回 Hash 对象的长度 |
length() |
返回 Hash 对象的长度 |
include?(key) |
判断是否包含指定的 key |
has_key?(key) |
判断是否包含指定的 key |
delete(key) |
删除指定 key 对应的元素 |
keys() |
返回由所有 key 组成的数组 |
values() |
返回由所有 value 组成的数组 |
举个例子:
student = {
"name" => "Steve",
"age" => 22,
"Gender" => "male"
}
p student.keys # => ["name", "Gender", "age"]
p student.values # => ["Steve", "male", 22]
puts student.include?("age") # => true
puts student.size # => 3
student.delete("Gender")
puts student.has_key?("Gender") # => false
puts student.size # => 2
当面对多层嵌套的哈希时,读写操作容易变得混乱。一个常见的解决方案是把哈希转换成对象,让每一个键都能像属性一样直接访问。下面的 HashObj 类就是为此设计的:
class HashObj
class << self
def load_from_hash(hash)
if hash.instance_of? Hash
obj = HashObj.new
hash.each{|k,v| obj.send :def_sget_method, k, HashObj.load_from_hash(v) }
obj
elsif hash.instance_of? Array
hash.map{|m| HashObj.load_from_hash(m) }
else
hash
end
end
end
def attributes
hash = {}
@@reg ||= /=/
self.singleton_methods.reject{|x| @@reg =~ x.to_s}.each do |m|
v = self.send(m)
if v.instance_of? HashObj
real_v = v.attributes
elsif v.instance_of? Array
real_v = []
v.each do |l|
if l.instance_of? HashObj
real_v << l.attributes
else
real_v << l
end
end
else
real_v = v
end
hash[m] = real_v
end
hash
end
protected
def def_sget_method(name, val)
self.instance_variable_set "@#{name}", val
self.define_singleton_method "#{name}=" do |n_val|
instance_variable_set "@#{name}", n_val
end
self.define_singleton_method name do
instance_variable_get "@#{name}"
end
end
end
使用示例:
hash = {
name: 'jack',
age: 22,
phone: ['61900871', '8787876'],
basic_info: { country: 'USA', city: 'New York' }
}
obj = HashObj.load_from_hash hash
obj.name # => 'jack'
obj.age # => 22
obj.phone # => ['61900871', '8787876']
obj.basic_info # =>
obj.basic_info.country # => 'USA'
obj.attributes == hash # => true
obj.age = 30
obj.attributes
# => {:name=>"jack", :age=>30, :phone=>["61900871", "8787876"], :basic_info=>{:country=>"USA", :city=>"New York"}}
这样一来,深层嵌套的哈希读写就变得和普通对象一样清晰了。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8