使用类常量作为 Ruby 哈希键

Posted

技术标签:

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

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


  SomeClassA: 'hash value',
  AnotherClass: 'hash value'

【问题讨论】:

只是好奇,你的用例是什么?为什么会有这样的要求? 【参考方案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" 

【讨论】:

以上是关于使用类常量作为 Ruby 哈希键的主要内容,如果未能解决你的问题,请参考以下文章

Ruby 符号的 Objective-C 等价物

为啥 Ruby 象征着我的哈希键?

ruby 哈希,其中键来自数组,值作为默认值

为啥关键字参数必须作为带有符号键的哈希传递,而不是 Ruby 中的字符串键?

ruby 符号作为键,但无法从哈希中获取值

如何将带有对象作为键的 Ruby 哈希对象作为 Map 对象发送到前端 Javascript