如果脚本中至少有两个相同字符串的实例,我应该使用符号吗?

推荐答案

TL;DR

一个简单的经验法则是每次需要内部标识符时都使用符号.对于Ruby<;2.2仅在非动态生成符号时使用符号,以避免内存泄漏.

Full answer

不将它们用于动态生成的标识符的唯一原因是内存问题.

这个问题很常见,因为许多编程语言没有符号,只有字符串,因此字符串也被用作代码中的标识符.你应该担心什么符号是meant to be,而不仅仅是when you should use symbols.符号就是标识符.如果你遵循这一理念,你很可能会把事情做好.

符号和字符串的实现有几个不同之处.关于符号,最重要的是它们是immutable.这意味着他们的价值永远不会改变.因此,符号的实例化速度比字符串快,而比较两个符号等操作也更快.

符号是不可变的这一事实允许Ruby在每次引用符号时使用相同的对象,从而节省内存.因此,每次解释器读取:my_key,它就可以从内存中获取它,而不是再次实例化它.这比每次初始化一个新字符串要便宜.

您可以使用命令Symbol.all_symbols获得所有已实例化符号的列表:

symbols_count = Symbol.all_symbols.count # all_symbols is an array with all 
                                         # instantiated symbols. 
a = :one
puts a.object_id
# prints 167778 

a = :two
puts a.object_id
# prints 167858

a = :one
puts a.object_id
# prints 167778 again - the same object_id from the first time!

puts Symbol.all_symbols.count - symbols_count
# prints 2, the two objects we created.

对于2.2之前的Ruby版本,一旦一个符号被实例化,这个内存将被删除.释放内存的唯一方法是重新启动应用程序.因此,符号也是错误使用时内存泄漏的主要原因.生成内存泄漏的最简单方法是在用户输入数据上使用方法to_sym,因为这些数据将始终更改,内存的新部分将永远在软件实例中使用.Ruby 2.2引入了symbol garbage collector,它释放了动态生成的符号,因此通过动态创建符号生成的内存泄漏不再是一个问题.

回答你的问题:

如果我的应用程序或脚本中至少有两个相同的字符串,那么我必须使用符号而不是字符串,这是真的吗?

如果您要寻找的是代码内部使用的标识符,那么应该使用符号.如果打印输出,应该使用字符串,即使它多次出现,甚至在内存中分配两个不同的对象.

原因如下:

  1. 打印符号将比打印字符串慢,因为它们被转换为字符串.
  2. 拥有大量不同的符号会增加应用程序的总体内存使用率,因为它们永远不会被释放.而且您永远不会同时使用代码中的所有字符串.

@AlanDert的用例

@AlanDert:如果我在haml代码中多次使用%input{type::checkbox}之类的东西,我应该使用什么作为复选框?

我:是的.

@AlanDert:但是要在html页面上打印符号,它应该转换成字符串,不是吗?那么使用它有什么意义呢?

输入的类型是什么?您想要使用的输入类型的标识符,或者您想要向用户显示的内容的标识符?

诚然,它在某个时候会变成HTML代码,但在编写代码的那一行时,它意味着是一个标识符——它标识出您需要什么类型的输入字段.因此,它会在代码中反复使用,并且始终具有与标识符相同的"字符串",不会产生内存泄漏.

也就是说,我们为什么不判断数据,看看字符串是否更快?

这是我为此创建的一个简单基准:

require 'benchmark'
require 'haml'

str = Benchmark.measure do
  10_000.times do
    Haml::Engine.new('%input{type: "checkbox"}').render
  end
end.total

sym = Benchmark.measure do
  10_000.times do
    Haml::Engine.new('%input{type: :checkbox}').render
  end
end.total

puts "String: " + str.to_s
puts "Symbol: " + sym.to_s

三项输出:

# first time
String: 5.14
Symbol: 5.07
#second
String: 5.29
Symbol: 5.050000000000001
#third
String: 4.7700000000000005
Symbol: 4.68

因此,使用smbols实际上比使用字符串快一点.为什么?这取决于HAML的实现方式.我需要对HAML代码进行一些修改才能看到,但是如果你继续在标识符的概念中使用符号,你的应用程序会更快、更可靠.当问题出现时,对其进行基准测试并获得答案.

Ruby相关问答推荐

Ruby:这两种混入模块方法是否等效?

如何在 Ruby 中验证来自多项 Select 提示的命令行输入?

在Ruby中按字母顺序对数组中的数组进行排序?

RSpec 是否有 python 类似功能来做 TDD?

Ruby:p *1..10中的星号是什么意思

Ruby检测方法

在 Ruby 中生成一个后台进程

从单独的文件中包含一个 Ruby 类

Ruby - 将块传递给方法

进程的 pid、ppid、uid、euid、gid 和 egid 有什么区别?

用零填充数字

为什么在 ruby​​ / rails / activerecord 中并不总是需要 self ?

困惑,像python,ruby这样的语言是单线程的吗?不像说java? (对于网络应用程序)

如何理解 class_eval() 和 instance_eval() 的区别?

运行 Ruby 命令时,PATH 中不安全的世界可写目录 /Users/username,模式 040777

Ruby:define_method 与 def

如果公司使用 C++、C# 或 Java 作为应用程序语言,为什么要学习 Perl、Python、Ruby?

Ruby哈希中的条件键/值

等号 ('=') 放在方法定义中的方法名称之后有什么作用?

如何使用#{variable}在Ruby中格式化带有浮点数的字符串?