哈希散列(“关键”)。关键在Ruby中

时间:2021-03-12 10:46:14

I have a a hash

我有一个散列

foo = {'bar'=>'baz'}

I would like to call foo.bar #=> 'baz'

我想叫foo。酒吧# = >“记者”

My motivation is rewriting an activerecord query into a raw sql query (using Model#find_by_sql). This returns a hash with the SELECT clause values as keys. However, my existing code relies on object.method dot notation. I'd like to do minimal code rewrite. Thanks.

我的动机是将activerecord查询重写为原始sql查询(使用Model#find_by_sql)。这将返回一个以SELECT子句值作为键的散列。但是,我现有的代码依赖于对象。点符号的方法。我想重写最小的代码。谢谢。

Edit: it appears Lua has this feature:

编辑:看来Lua有以下功能:

point = { x = 10, y = 20 }   -- Create new table
print(point["x"])            -- Prints 10
print(point.x)               -- Has exactly the same meaning as line above

5 个解决方案

#1


81  

>> require 'ostruct'
=> []
>> foo = {'bar'=>'baz'}
=> {"bar"=>"baz"}
>> foo_obj = OpenStruct.new foo
=> #<OpenStruct bar="baz">
>> foo_obj.bar
=> "baz"
>>

#2


35  

What you're looking for is called OpenStruct. It's part of the standard library.

你要找的是OpenStruct。它是标准库的一部分。

#3


22  

A good solution:

一个好的解决方案:

class Hash
  def method_missing(method, *opts)
    m = method.to_s
    if self.has_key?(m)
      return self[m]
    elsif self.has_key?(m.to_sym)
      return self[m.to_sym]
    end
    super
  end
end

Note: this implementation has only one known bug:

注意:此实现只有一个已知的bug:

x = { 'test' => 'aValue', :test => 'bar'}
x.test # => 'aValue'

If you prefer symbol lookups rather than string lookups, then swap the two 'if' condition

如果您更喜欢符号查找而不是字符串查找,那么请交换这两个“If”条件

#4


6  

Rather than copy all the stuff out of the hash, you can just add some behaviour to Hash to do lookups.

与其从散列中复制所有的内容,还可以添加一些行为到散列中进行查找。

If you add this defintion, you extend Hash to handle all unknown methods as hash lookups:

如果您添加了这个定义,您将散列扩展为散列查找来处理所有未知的方法:

class Hash
  def method_missing(n)
    self[n.to_s]
  end
end

Bear in mind that this means that you won't ever see errors if you call the wrong method on hash - you'll just get whatever the corresponding hash lookup would return.

请记住,这意味着如果在散列上调用了错误的方法,您将不会看到错误——您将得到相应的散列查找将返回的任何内容。

You can vastly reduce the debugging problems this can cause by only putting the method onto a specific hash - or as many hashes as you need:

只需将方法放入特定的散列中,或者根据需要使用任意数量的散列,就可以大大减少调试问题的发生:

a={'foo'=>5, 'goo'=>6}
def a.method_missing(n)
   self[n.to_s]
end

The other observation is that when method_missing gets called by the system, it gives you a Symbol argument. My code converted it into a String. If your hash keys aren't strings this code will never return those values - if you key by symbols instead of strings, simply substitute n for n.to_s above.

另一个观察是,当method_missing被系统调用时,它会给你一个符号参数。我的代码将它转换成字符串。如果你的哈希键不是字符串,这段代码将永远不会返回这些值——如果你用符号而不是字符串来键入,只需用n替换n。to_s以上。

#5


4  

There are a few gems for this. There's my recent gem, hash_dot, and a few other gems with similar names I discovered as I released mine on RubyGems, including dot_hash.

这里有一些宝石。这是我最近开发的gem hash_dot和其他一些名称与我在RubyGems上发布时发现的类似的gem,包括dot_hash。

HashDot allows dot notation syntax, while still addressing concerns about NoMethodErrors addressed by @avdi. It is faster, and more traversable than an object created with OpenStruct.

HashDot允许使用点表示法语法,但仍然可以处理@avdi所处理的关于NoMethodErrors的问题。它比使用OpenStruct创建的对象更快、更可遍历。

require 'hash_dot'
a = {b: {c: {d: 1}}}.to_dot
a.b.c.d => 1

require 'open_struct'
os = OpenStruct.new(a)
os.b => {c: {d: 1}}
os.b.c.d => NoMethodError

It also maintains expected behavior when non-methods are called.

它还在调用非方法时维护预期的行为。

a.non_method => NoMethodError

Please feel free to submit improvements or bugs to HashDot.

请随意向HashDot提交改进或bug。

#1


81  

>> require 'ostruct'
=> []
>> foo = {'bar'=>'baz'}
=> {"bar"=>"baz"}
>> foo_obj = OpenStruct.new foo
=> #<OpenStruct bar="baz">
>> foo_obj.bar
=> "baz"
>>

#2


35  

What you're looking for is called OpenStruct. It's part of the standard library.

你要找的是OpenStruct。它是标准库的一部分。

#3


22  

A good solution:

一个好的解决方案:

class Hash
  def method_missing(method, *opts)
    m = method.to_s
    if self.has_key?(m)
      return self[m]
    elsif self.has_key?(m.to_sym)
      return self[m.to_sym]
    end
    super
  end
end

Note: this implementation has only one known bug:

注意:此实现只有一个已知的bug:

x = { 'test' => 'aValue', :test => 'bar'}
x.test # => 'aValue'

If you prefer symbol lookups rather than string lookups, then swap the two 'if' condition

如果您更喜欢符号查找而不是字符串查找,那么请交换这两个“If”条件

#4


6  

Rather than copy all the stuff out of the hash, you can just add some behaviour to Hash to do lookups.

与其从散列中复制所有的内容,还可以添加一些行为到散列中进行查找。

If you add this defintion, you extend Hash to handle all unknown methods as hash lookups:

如果您添加了这个定义,您将散列扩展为散列查找来处理所有未知的方法:

class Hash
  def method_missing(n)
    self[n.to_s]
  end
end

Bear in mind that this means that you won't ever see errors if you call the wrong method on hash - you'll just get whatever the corresponding hash lookup would return.

请记住,这意味着如果在散列上调用了错误的方法,您将不会看到错误——您将得到相应的散列查找将返回的任何内容。

You can vastly reduce the debugging problems this can cause by only putting the method onto a specific hash - or as many hashes as you need:

只需将方法放入特定的散列中,或者根据需要使用任意数量的散列,就可以大大减少调试问题的发生:

a={'foo'=>5, 'goo'=>6}
def a.method_missing(n)
   self[n.to_s]
end

The other observation is that when method_missing gets called by the system, it gives you a Symbol argument. My code converted it into a String. If your hash keys aren't strings this code will never return those values - if you key by symbols instead of strings, simply substitute n for n.to_s above.

另一个观察是,当method_missing被系统调用时,它会给你一个符号参数。我的代码将它转换成字符串。如果你的哈希键不是字符串,这段代码将永远不会返回这些值——如果你用符号而不是字符串来键入,只需用n替换n。to_s以上。

#5


4  

There are a few gems for this. There's my recent gem, hash_dot, and a few other gems with similar names I discovered as I released mine on RubyGems, including dot_hash.

这里有一些宝石。这是我最近开发的gem hash_dot和其他一些名称与我在RubyGems上发布时发现的类似的gem,包括dot_hash。

HashDot allows dot notation syntax, while still addressing concerns about NoMethodErrors addressed by @avdi. It is faster, and more traversable than an object created with OpenStruct.

HashDot允许使用点表示法语法,但仍然可以处理@avdi所处理的关于NoMethodErrors的问题。它比使用OpenStruct创建的对象更快、更可遍历。

require 'hash_dot'
a = {b: {c: {d: 1}}}.to_dot
a.b.c.d => 1

require 'open_struct'
os = OpenStruct.new(a)
os.b => {c: {d: 1}}
os.b.c.d => NoMethodError

It also maintains expected behavior when non-methods are called.

它还在调用非方法时维护预期的行为。

a.non_method => NoMethodError

Please feel free to submit improvements or bugs to HashDot.

请随意向HashDot提交改进或bug。