Ruby符号是否存在,因为字符串是可变的而不是实体的?

时间:2017-06-19 15:08:09

标签: ruby

我已经使用Ruby大约一年了,并且有一个语言问题:是否需要符号,因为Ruby字符串是可变的而且没有实习?

在Java中,字符串是不可变的和实际的。所以“foo”在值和引用中总是等于“foo”,它的值不能改变。在Ruby中,字符串是可变的而不是实体,因此"a".object_id == "a".object_id将是错误的。

如果Ruby实现了像Java这样的字符串,那么符号就没有必要了,对吗?

4 个答案:

答案 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中修补。

请参阅Getting warning : Denial of Service

答案 2 :(得分:2)

类似Java的字符串将取代符号的功能,因此从这个意义上讲,你是正确的。但是,我不认为Matz会对一种只有不可变和实习字符串的语言感到满意。

使用字符串和符号,Ruby提供了两全其美的优势。符号为只读字符串(如散列键)提供内存效率,而可变字符串对于字符串操作(如串联)具有内存效率。

所以也许"如果Ruby实现了像Java这样的字符串"不是正确的思路。 Ruby 实现了像Java这样的字符串。他们称之为#34;符号。"然后Ruby实现了第二种类型的字符串,它称之为"字符串。"命名纯粹是美学,但我认为这是有道理的。

答案 3 :(得分:2)

  

我已经和Ruby一起工作了大约一年,并且有一个语言问题:因为Ruby字符串是可变的而不是实习,所以这些符号是必需的吗?

没有

SymbolString只是两种不同的数据类型。 String用于文字,Symbol用于标记。

  

比方说,Java,字符串是不可变的和实习的。

不,他们不是。它们是不可变的,有时是实习,有时则不是。如果String被实习,那么为什么有一个方法java.lang.String.intern()来实习String? Java中的String仅在

时实现
  • 您致电java.lang.String.intern()
  • StringString文字表达式或
  • 的结果
  • StringString - 类型常量值表达式
  • 的结果

否则,他们不是。

  

所以" 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 Symbolkeywords完全等同于Ruby' { {1}},他们评价自己,只为自己而战。 Symbols OTOH 可能代表别的东西。

Erlangimmutable stringsatoms,就像Clojure / Lisp符号一样。

ECMAScriptimmutable strings,最近添加了Symbol数据类型。但是,它们并不是100%等同于Ruby Symbol,因为它们还有一个额外的保证:它们不仅仅评估自己并且仅仅为自己而且它们也是不可伪造的(这意味着它不可能创建) Symbol等于另一个Symbol)。

请注意,Ruby正在远离可变字符串:

  • Ruby 2.1优化模式Symbol以从全局字符串池返回冻结字符串。
  • Ruby 2.3引入了'literal string'.freeze pragma和# frozen_string_literal: true功能切换开关,默认情况下,在每个脚本(pragma)或每个进程上冻结(和池化)所有字符串文字(功能切换)基础。
  • Ruby 3会将这两者的默认值切换为--enable=frozen-string-literal,因此您必须明确说出true# frozen_string_literal: false才能获得当前行为。
  • 某些更高版本将完全删除对可变字符串的支持。