我已经使用Ruby大约一年了,并且有一个语言问题:是否需要符号,因为Ruby字符串是可变的而且没有实习?
在Java中,字符串是不可变的和实际的。所以“foo”在值和引用中总是等于“foo”,它的值不能改变。在Ruby中,字符串是可变的而不是实体,因此"a".object_id == "a".object_id
将是错误的。
如果Ruby实现了像Java这样的字符串,那么符号就没有必要了,对吗?
答案 0 :(得分:5)
从Ruby 2.3开始,不可变的String
已经通过RUBYOPT
标志--enable-frozen-string-literals
可选地实现了
即。
RUBYOPT=--enable-frozen-string-literals ruby /some/file
这会导致所有String
文字(使用""
,%q{}
,%Q{}
或“#{}”样式创建的字符串)变为不可变。此功能目前被认为是Ruby 3.0的默认功能。 Follow along with Feature#11473。此功能在文件级别而非全局级别上也可用作“魔术评论”
# frozen_string_literal: true
这与RUBYOPT
版本具有相同的影响,但仅适用于特定文件。 (另一种方式是直接与VM交互RubyVM::InstructionSequence.compile_option = {frozen_string_literal: true}
)
由于这是可选的,显然它可以打开和关闭,并且仍然是3.0中的一个选项,只是默认为打开而不是关闭。仍然可以使用String
创建可变String.new
,并且String
可以dup
以使其dup
计数器部分可变。 (请注意以上内容:插值"#{}"
也会因""
而创建新的不可变字符串)
所有这一切都没有取代红宝石中Symbols
的需要。首先,支持ruby的基础C
通过Symbols
大量利用rb_itern
来处理方法定义之类的引用(这些引用标题为“Immortal Symbols”永远不会被GCed)。
此外Symbols
就像ruby中的所有内容一样,都是他们自己的Object
,并且拥有自己有用的功能集。以Symbol#to_proc
为例。这起源于猴子补丁解决方案的语法简易性,并在1.8.7中被用于核心。这种风格受到红宝石社区的高度鼓励和定期利用。请告知您如何使用String
代替Symbol
建议降低此功能。
虽然Symbols
曾被认为有点“危险”(缺乏更好的词),因为他们的拘禁和记忆消耗与红宝石的动态相结合。从Ruby 2.2开始,大多数Symbols
(见上文)可以被垃圾收集,即通过String
内容(#intern
,#to_sym
等在红宝石内创建的符号。 (这些已被创造“凡人符号”)
小警告包括
之类的内容 define_method(param[:meth].to_sym) {}
这似乎是因为它正在调用to_sym
它应该是“凡人符号”,但是因为define_method
调用rb_intern
来保持方法引用它实际上会创建一个“不朽的符号”
希望这次失败有助于解释Symbol
在ruby中的必要性,不仅从开发人员的角度来看,而且还有大量使用作为ruby实现的C
内部的一部分。
答案 1 :(得分:2)
差不多,是的。我的理解是编译器保留一个符号表,它可以动态增长。这就是为什么你必须永远不要接受用户输入并将其取消选中转换为符号的原因,因为你可以创建所谓的符号溢出攻击。
我相信符号溢出漏洞已在Ruby 2.2中修补。
答案 2 :(得分:2)
类似Java的字符串将取代符号的功能,因此从这个意义上讲,你是正确的。但是,我不认为Matz会对一种只有不可变和实习字符串的语言感到满意。
使用字符串和符号,Ruby提供了两全其美的优势。符号为只读字符串(如散列键)提供内存效率,而可变字符串对于字符串操作(如串联)具有内存效率。
所以也许"如果Ruby实现了像Java这样的字符串"不是正确的思路。 Ruby 实现了像Java这样的字符串。他们称之为#34;符号。"然后Ruby实现了第二种类型的字符串,它称之为"字符串。"命名纯粹是美学,但我认为这是有道理的。
答案 3 :(得分:2)
我已经和Ruby一起工作了大约一年,并且有一个语言问题:因为Ruby字符串是可变的而不是实习,所以这些符号是必需的吗?
没有
Symbol
和String
只是两种不同的数据类型。 String
用于文字,Symbol
用于标记。
比方说,Java,字符串是不可变的和实习的。
不,他们不是。它们是不可变的,有时是实习,有时则不是。如果String
被实习,那么为什么有一个方法java.lang.String.intern()
来实习String
? Java中的String
仅在
java.lang.String.intern()
或String
是String
文字表达式或String
是String
- 类型常量值表达式否则,他们不是。
所以" foo"总是等于" foo"价值和参考,其价值不能改变。
同样,事实并非如此:
class Test {
public static void main(String... args) {
System.out.println("foo".equals(args[0]));
System.out.println("foo" == args[0]);
}
}
用
调用它java Test foo
# true
# false
在Ruby中,字符串是可变的而不是实体,因此
"a".object_id == "a".object_id
将是错误的。
在现代Ruby中,这也不一定正确:
#frozen_string_literal: true
"a".object_id == "a".object_id
#=> true
如果Ruby实现了像Java这样的字符串,那么符号是不必要的,对吧?
没有。就像我说的,它们是不同用例的不同类型。
例如,看一下Scala,它实现了#Java;#Java;#34;等字符串。 (事实上,在Scala的JVM实现上,there is no String
,Scala String
只是是 java.lang.String
)。然而,它也有一个Symbol
类。
同样地,Clojure没有一个像两个这样的数据类型,例如Ruby Symbol
:keywords完全等同于Ruby' { {1}},他们评价自己,只为自己而战。 Symbols OTOH 可能代表别的东西。
Erlang有immutable strings和atoms,就像Clojure / Lisp符号一样。
ECMAScript有immutable strings,最近添加了Symbol
数据类型。但是,它们并不是100%等同于Ruby Symbol
,因为它们还有一个额外的保证:它们不仅仅评估自己并且仅仅为自己而且它们也是不可伪造的(这意味着它不可能创建) Symbol
等于另一个Symbol
)。
请注意,Ruby正在远离可变字符串: