【问题标题】:Use class constant as Ruby hash key使用类常量作为 Ruby 哈希键
【发布时间】:2018-02-19 03:07:51
【问题描述】:

我知道我可以使用类作为哈希键,但这是一个好习惯吗?在性能或测试方面有什么缺点吗?

{
  SomeClassA: 'hash value',
  AnotherClass: 'hash value'
}

【问题讨论】:

  • 只是好奇,你的用例是什么?为什么会有这样的要求?

标签: ruby-on-rails ruby


【解决方案1】:
{
  SomeClassA: 'hash value',
  AnotherClass: 'hash value'
}

实际上相当于:

{
  :SomeClassA => 'hash value',
  :AnotherClass => 'hash value'
}

键是符号。在“新”文字哈希语法中,键只是被视为转换为符号的文字(只要它们是有效的语法)。

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

{
  SomeClassA => 'hash value',
  AnotherClass => 'hash value'
}

这是一个好习惯吗?

这是一种可以在少数有限情况下使用的技术。例如替换一系列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

但无论如何,我宁愿在此处使用 case 语句,因为它的意图更清晰,更灵活。

在性能或测试方面有什么缺点吗?

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

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

class Foo < ApplicationRecord
  belongs_to :bar, class_name: "Baz"
end

它让 Rails 在需要时懒加载 Baz。你可以对上面的例子做同样的事情:

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

【讨论】:

  • 谢谢,这就是我要找的东西,但是 bar.name.to_sym 如何解决这里的自动加载问题?能给我举个例子吗?如果在大多数情况下只通过 foo(SomeClassA) 似乎没问题会发生什么?
  • "...强制您放入密钥中的任何内容.." 可能有点强。 'Yes' 用于字符串、常量以及局部变量和方法的名称(不带前导冒号),但据我所知,'no' 用于其他任何东西(整数、浮点数、符号、实例名称、类和全局变量、数组,哈希值等)。您可能希望更具体。除了那个小问题,很好的答案。
  • 有效点@CarySwoveland。它实际上只是将以任何字母开头的字符串强制转换为符号,因为其他任何内容都会导致语法错误,即使是 { 0_foo: 2 }
  • 那是因为:0_foo 无效。您必须改用:'0_foo'{ '0_foo': 2 }
  • 没错,就是在解析hash的时候进行语法检查。但同样的规则应该适用。 (IIRC,有一个 Ruby 版本无法解析带引号的符号键)
【解决方案2】:

虽然你可以做到,但我想不出使用它的理由。使用符号或字符串作为键更有效,因为程序不必加载整个类。 (旁注,正如其他人指出的那样,您的示例实际上是使用符号键,您需要使用哈希火箭来使用类名作为键)

【讨论】:

    【解决方案3】:

    你所拥有的不是类键而是符号。 试试

    class A
    end
    
    class B
    end
    
    hash = {A: "Some", B: "Code"}
    hash.keys[0].class
    => Symbol
    

    但还是A.class => Class

    在符号性能的情况下,POST 很棒

    您还可以查看有关 user-defined class as hash keys 的 ruby​​ 文档

    【讨论】:

    • +1 但在您的答案中声明 A 类和 B 类是无关紧要的,而且对于您为什么这样做,您不觉得吗?
    【解决方案4】:

    该哈希使用符号而不是类作为键,但您可以通过这样做使用Class

    hash = { SomeClassA => "some value" }
    

    我想不出为什么它会比使用任何其他对象更糟糕,因为

    Ruby 中的类是一等对象——每个都是类 Class 的一个实例

    所以

    { SomeClassA => "some value" }
    

    在功能上等同于

    { "Some String" => "some value" }
    

    【讨论】:

      猜你喜欢
      • 2017-03-23
      • 2011-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-16
      • 2018-06-17
      • 2020-07-02
      • 1970-01-01
      相关资源
      最近更新 更多