哈希值中的值是否可以引用其他值?

时间:2013-01-08 12:31:10

标签: ruby hash

我有这样的哈希:

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"

2 个答案:

答案 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']
  }
}

您还可以编写一个帮助方法从该哈希中提取给定的别名。但我不确定它是否值得。