使用类常量作为Ruby哈希键

use*_*793 2 ruby ruby-on-rails

我知道我可以使用class作为Hash键,但这是一个好习惯吗?在性能或测试方面有任何缺点吗?

{
  SomeClassA: 'hash value',
  AnotherClass: 'hash value'
}
Run Code Online (Sandbox Code Playgroud)

max*_*max 7

{
  SomeClassA: 'hash value',
  AnotherClass: 'hash value'
}
Run Code Online (Sandbox Code Playgroud)

实际上相当于:

{
  :SomeClassA => 'hash value',
  :AnotherClass => 'hash value'
}
Run Code Online (Sandbox Code Playgroud)

键是符号.在"新"文字散列语法中,键被视为文字,它们被转换为符号(前提是它们是有效的语法).

要使用常量,范围或任何其他类型的对象,您可以将梦想作为使用hashrockets所需的键:

{
  SomeClassA => 'hash value',
  AnotherClass => 'hash value'
}
Run Code Online (Sandbox Code Playgroud)

这是一个好习惯吗?

它是一种可以在少数有限情况下使用的技术.例如,替换一系列if语句.

def foo(bar)
  if bar.is_a? SomeClassA
    'hash value'
  end
  if bar.is_a? AnotherClass
    'another value'
  end
end

def foo(bar)
  {
    SomeClassA => 'hash value',
    AnotherClass => 'another value'
  }[bar]
end
Run Code Online (Sandbox Code Playgroud)

但我宁愿在那里使用案例陈述,因为它的意图更清晰,更灵活.

在性能或测试方面有任何缺点吗?

您创建的每个哈希都会包含指向内存中完全相同对象的键,就像您使用符号一样.

一个很大的问题是Rails猴子补丁const_missing到自动加载文件 - 当你引用类名时rails会将文件从文件系统加载到内存中.这就是你声明与以下关联的原因:

class Foo < ApplicationRecord
  belongs_to :bar, class_name: "Baz"
end
Run Code Online (Sandbox Code Playgroud)

它允许Rails在需要时延迟加载Baz.您将通过以下示例执行相同的操作:

def foo(bar)
  {
    'SomeClassA' => 'hash value',
    'AnotherClass' => 'another value'
  }[bar.name]
end
Run Code Online (Sandbox Code Playgroud)