符号在ruby中的作用是什么?字符串和符号有什么区别?为什么动态创建大量符号不是一个好主意?
uxhixvfz1#
符号就像字符串,但它们是不可变的--不能修改。它们只被放入内存一次,这使得它们在处理哈希值中的密钥等事情时非常有效,但它们会一直留在内存中直到程序退出,如果你误用它们,这会使它们占用大量内存。如果动态创建大量符号,则会分配大量内存,这些内存在程序结束之前无法释放(edit:不再是since Ruby 2.2的情况)。只有当您知道将执行以下操作时,才应动态创建符号(使用string.to_sym):1.需要重复访问符号1.不需要修改它们正如我之前所说的,符号对于像散列这样的东西很有用--在这种情况下,你更关心变量的标识,而不是它的值。符号,如果使用得当,是传递标识的一种可读和有效的方式。我将解释我的意思是什么不变性的符号回复您的评论。字符串就像数组;它们可以在适当的位置进行修改:
string.to_sym
12:17:44 ~$ irb irb(main):001:0> string = "Hello World!" => "Hello World!" irb(main):002:0> string[5] = 'z' => "z" irb(main):003:0> string => "HellozWorld!" irb(main):004:0>
符号更像数字;它们不能被就地编辑:
irb(main):011:0> symbol = :Hello_World => :Hello_World irb(main):012:0> symbol[5] = 'z' NoMethodError: undefined method `[]=' for :Hello_World:Symbol from (irb):12 from :0
8zzbczxx2#
无论在何处使用,符号都是相同的对象和相同的内存分配:
>> :hello.object_id => 331068 >> a = :hello => :hello >> a.object_id => 331068 >> b = :hello => :hello >> b.object_id => 331068 >> a = "hello" => "hello" >> a.object_id => 2149256980 >> b = "hello" => "hello" >> b.object_id => 2149235120 >> b = "hell" + "o"
两个“相同”的字符串,因为它们包含相同的字符,可能不会引用相同的内存,如果你使用字符串,比如说,散列,这可能是低效的。因此,符号可以有效地减少内存开销。然而,它们是一个等待发生的内存泄漏,因为符号一旦创建就不能被垃圾收集。创建成千上万的符号将分配内存,并且不可恢复。哎呀!
yb3bgrhw3#
从用户输入创建符号而不验证输入是否符合某种白名单(例如,RoR中的查询字符串参数)是非常糟糕的。如果用户输入在没有验证的情况下转换为符号,恶意用户可能会导致程序消耗大量内存,而这些内存永远不会被垃圾收集。错误(无论用户输入如何,都会创建符号):
name = params[:name].to_sym
良好(仅当允许用户输入时才创建符号):
whitelist = ['allowed_value', 'another_allowed_value'] raise ArgumentError unless whitelist.include?(params[:name]) name = params[:name].to_sym
yjghlzjz4#
Starting Ruby 2.2及更高版本Symbols会自动进行垃圾收集,因此这不应成为问题。
7jmck4yq5#
如果您使用的是Ruby 2.2.0或更高版本,动态创建大量符号通常是可以的,因为它们将根据Ruby 2.2.0-preview1 announcement进行垃圾收集,Ruby 2.2.0-preview1 announcement具有到more details about the new symbol GC的链接。(C源代码中使用的一个内部Ruby实现概念),那么在这种情况下,它将被固定,永远不会被垃圾收集。你可以把符号看作是某个东西的名字,而字符串(大致)表示为字符序列。在许多情况下,您可以使用符号或字符串,或者可以使用两者的混合。符号是不可变的,这意味着它们在创建后不能更改。符号的实现方式是,比较两个符号以查看它们是否相等是非常有效的。所以用它们作为哈希的键应该比用字符串快一些,Symbols没有字符串的很多方法,比如start_with?,所以在调用这些方法之前,你必须用to_s把符号转换成字符串。您可以在文档中阅读有关符号的详细信息:http://www.ruby-doc.org/core-2.1.3/Symbol.html
start_with?
to_s
5条答案
按热度按时间uxhixvfz1#
符号就像字符串,但它们是不可变的--不能修改。
它们只被放入内存一次,这使得它们在处理哈希值中的密钥等事情时非常有效,但它们会一直留在内存中直到程序退出,如果你误用它们,这会使它们占用大量内存。
如果动态创建大量符号,则会分配大量内存,这些内存在程序结束之前无法释放(edit:不再是since Ruby 2.2的情况)。只有当您知道将执行以下操作时,才应动态创建符号(使用
string.to_sym
):1.需要重复访问符号
1.不需要修改它们
正如我之前所说的,符号对于像散列这样的东西很有用--在这种情况下,你更关心变量的标识,而不是它的值。符号,如果使用得当,是传递标识的一种可读和有效的方式。
我将解释我的意思是什么不变性的符号回复您的评论。
字符串就像数组;它们可以在适当的位置进行修改:
符号更像数字;它们不能被就地编辑:
8zzbczxx2#
无论在何处使用,符号都是相同的对象和相同的内存分配:
两个“相同”的字符串,因为它们包含相同的字符,可能不会引用相同的内存,如果你使用字符串,比如说,散列,这可能是低效的。
因此,符号可以有效地减少内存开销。然而,它们是一个等待发生的内存泄漏,因为符号一旦创建就不能被垃圾收集。创建成千上万的符号将分配内存,并且不可恢复。哎呀!
yb3bgrhw3#
从用户输入创建符号而不验证输入是否符合某种白名单(例如,RoR中的查询字符串参数)是非常糟糕的。如果用户输入在没有验证的情况下转换为符号,恶意用户可能会导致程序消耗大量内存,而这些内存永远不会被垃圾收集。
错误(无论用户输入如何,都会创建符号):
良好(仅当允许用户输入时才创建符号):
yjghlzjz4#
Starting Ruby 2.2及更高版本Symbols会自动进行垃圾收集,因此这不应成为问题。
7jmck4yq5#
如果您使用的是Ruby 2.2.0或更高版本,动态创建大量符号通常是可以的,因为它们将根据Ruby 2.2.0-preview1 announcement进行垃圾收集,Ruby 2.2.0-preview1 announcement具有到more details about the new symbol GC的链接。(C源代码中使用的一个内部Ruby实现概念),那么在这种情况下,它将被固定,永远不会被垃圾收集。
你可以把符号看作是某个东西的名字,而字符串(大致)表示为字符序列。在许多情况下,您可以使用符号或字符串,或者可以使用两者的混合。符号是不可变的,这意味着它们在创建后不能更改。符号的实现方式是,比较两个符号以查看它们是否相等是非常有效的。所以用它们作为哈希的键应该比用字符串快一些,Symbols没有字符串的很多方法,比如
start_with?
,所以在调用这些方法之前,你必须用to_s
把符号转换成字符串。您可以在文档中阅读有关符号的详细信息:
http://www.ruby-doc.org/core-2.1.3/Symbol.html