Bạn có thể lười biếng, và gói nó trong lambda
:
my_hash = YAML.load_file('yml')
my_lamb = lambda { |key| my_hash[key.to_s] }
my_lamb[:a] == my_hash['a'] #=> true
Nhưng điều này sẽ chỉ làm việc để đọc từ hàm băm - không viết.
Để làm điều đó, bạn có thể sử dụng Hash#merge
my_hash = Hash.new { |h,k| h[k] = h[k.to_s] }.merge(YAML.load_file('yml'))
Khối init sẽ chuyển đổi các khóa một lần theo yêu cầu, mặc dù nếu bạn cập nhật giá trị cho phiên bản chuỗi của khóa sau khi truy cập phiên bản ký hiệu, phiên bản ký hiệu sẽ không được cập nhật.
irb> x = { 'a' => 1, 'b' => 2 }
#=> {"a"=>1, "b"=>2}
irb> y = Hash.new { |h,k| h[k] = h[k.to_s] }.merge(x)
#=> {"a"=>1, "b"=>2}
irb> y[:a] # the key :a doesn't exist for y, so the init block is called
#=> 1
irb> y
#=> {"a"=>1, :a=>1, "b"=>2}
irb> y[:a] # the key :a now exists for y, so the init block is isn't called
#=> 1
irb> y['a'] = 3
#=> 3
irb> y
#=> {"a"=>3, :a=>1, "b"=>2}
Bạn cũng có thể có khối init không cập nhật hàm băm, điều này sẽ bảo vệ bạn khỏi loại lỗi đó, nhưng bạn vẫn dễ bị tổn thương ngược lại - cập nhật phiên bản biểu tượng sẽ không cập nhật phiên bản chuỗi:
irb> q = { 'c' => 4, 'd' => 5 }
#=> {"c"=>4, "d"=>5}
irb> r = Hash.new { |h,k| h[k.to_s] }.merge(q)
#=> {"c"=>4, "d"=>5}
irb> r[:c] # init block is called
#=> 4
irb> r
#=> {"c"=>4, "d"=>5}
irb> r[:c] # init block is called again, since this key still isn't in r
#=> 4
irb> r[:c] = 7
#=> 7
irb> r
#=> {:c=>7, "c"=>4, "d"=>5}
Vì vậy, điều cần cẩn thận với những điều này là chuyển đổi giữa hai hình thức chính. Gắn bó với một.