我有这样的哈希:
config = {
:assets => {
:path => '/assets',
:aliases => {
'/assets/' => '/assets/index.html',
'/assets/index.htm' => '/assets/index.html'
}
},
:api => {
:path => '/auth/api',
:aliases => {
'/auth/api/me' => '/auth/api/whoami'
}
}
}
是否可以删除重复项并按config[...][:aliases]
config[...][:path]
分配"#{dict_im_in()[:path]}/index.html"
?
答案 0 :(得分:1)
你想要做的是过早优化的气味。我建议你在哈希中尽可能地集中使用符号作为键和值。符号内存非常高效且查找速度快,因为Ruby只会为给定符号创建一个内存插槽,从而有效地完成您正在尝试的操作。
您的示例结构可以使用符号重写:
config = {
:assets => {
:path => :'/assets',
:aliases => {
:'/assets/' => :'/assets/index.html',
:'/assets/index.htm' => :'/assets/index.html'
}
},
:api => {
:path => :'/auth/api',
:aliases => {
:'/auth/api/me' => :'/auth/api/whoami'
}
}
}
:'/assets/index.html'
,无论在哪里,都会指向相同的符号,与字符串不同。
每当您需要访问期望字符串的值时,请对其to_s
执行操作。添加值时,请对其执行to_sym
。
在幕后,您将在Hash中更有效地使用内存,并使用Ruby中可用的最快值查找。
现在,如果您使用哈希结构配置应用程序,并将其存储在磁盘上,则可以使用YAML节省一些空间,YAML在其数据文件中支持aliases and anchors。在解析为Ruby对象后,它们不会在散列内部生成指针,但它们可以减小文件的大小。
编辑:
如果需要动态定义配置,则为各种字符串的所有子部分创建变量,然后添加生成它的方法。以下是动态创建此类内容的基础知识:
require 'awesome_print'
def make_config(
assets = '/assets',
index_html = 'index.html',
auth_api = '/auth/api'
)
assets_index = File.join(assets, index_html)
{
:assets => {
:path => assets,
:aliases => {
assets + '/' => assets_index,
assets_index[0..-2] => assets_index
}
},
:api => {
:path => auth_api,
:aliases => {
File.join(auth_api, 'me') => File.join(auth_api, 'whoami')
}
}
}
end
ap make_config()
ap make_config(
'/new_assets',
['new','path','to','index.html'],
'/auth/new_api'
)
将产生什么:
{
:assets => {
:path => "/assets",
:aliases => {
"/assets/" => "/assets/index.html",
"/assets/index.htm" => "/assets/index.html"
}
},
:api => {
:path => "/auth/api",
:aliases => {
"/auth/api/me" => "/auth/api/whoami"
}
}
}
和
{
:assets => {
:path => "/new_assets",
:aliases => {
"/new_assets/" => "/new_assets/new/path/to/index.html",
"/new_assets/new/path/to/index.htm" => "/new_assets/new/path/to/index.html"
}
},
:api => {
:path => "/auth/new_api",
:aliases => {
"/auth/new_api/me" => "/auth/new_api/whoami"
}
}
}
编辑:
复制值指针的另一种方法是创建返回所需信息的lambda或proc。我认为它们就像它们是C或Perl中的函数指针一样,允许我们保留范围内变量的状态,或者操纵传入的值。这不是一个完美的解决方案,因为发生了变量范围,但它是该框的另一个工具:
lambda1 = lambda { 'bar' }
proc2 = Proc.new { |a,b| a + b }
proc3 = Proc.new { proc2.call(1,2) }
foo = {
:key1 => lambda1,
:key2 => proc2,
:key3 => proc2,
:key4 => proc3
}
foo[:key1].object_id # => 70222460767180
foo[:key2].object_id # => 70222460365960
foo[:key3].object_id # => 70222460365960
foo[:key4].object_id # => 70222460149600
foo[:key1].call # => "bar"
foo[:key2].call(1, 2) # => 3
foo[:key3].call(%w[a b]) # => "ab"
foo[:key4].call # => 3
有关lambdas和procs的更多信息,请参阅“When to use lambda, when to use Proc.new?”。
答案 1 :(得分:-1)
这是一个有趣的问题;)。
我认为您可以“重新打开”哈希,然后只使用变量名称。
例如:
config = {
:assets => {
:path => '/assets',
:aliases => {
'/assets/' => '/assets/index.html',
'/assets/index.htm' => '/assets/index.html'
}
}
}
# Then "re-open" the Hash
config[:api] = {
:path => '/auth/api',
:aliases => {
'/auth/api/me' => config[:assets][:aliases]['/assets/index.htm']
}
}
您还可以编写一个帮助方法从该哈希中提取给定的别名。但我不确定它是否值得。