String.new和Ruby中的字符串文字之间的区别是什么?

时间:2017-01-12 00:05:59

标签: ruby

我很难看到为String对象的新实例创建值的过程与创建String文字的值有何不同。

a = String.new("Hello")
# => "Hello"

b = "Hello"
# => "Hello"

如果我跑

a == b
# => true

相同的价值观!发生了什么事?

4 个答案:

答案 0 :(得分:4)

字符串文字是一个字符串对象。早期版本的Ruby没有区别。

从Ruby 2.3开始,您可以选择冻结字符串文字。这是Ruby 3.0中的计划默认值

这意味着......

x = String.new("Hello")
x.upcase!

...会产生错误,因为字符串不可变。

使用构造函数......

from nltk import sent_tokenize, word_tokenize
from nltk.tag import StanfordNERTagger

st = StanfordNERTagger('english.muc.7class.distsim.crf.ser.gz','stanford-ner.jar')

i= "He was born on October 15, 1931 at Dhanushkothi in the temple town Rameshwaram in Tamil Nadu."

words = word_tokenize(i)
namedEnt = st.tag(words)

print namedEnt

工作正常。

答案 1 :(得分:1)

在您的示例中,ab是类似c的引用,而不是指针。所以你要比较的是价值而不是对象。

答案 2 :(得分:1)

  

相同的价值观!发生了什么事?

没有什么特别的,你可以用相同的值创建无限数量的局部变量。

您可以使用Object#object_id查看这些变量实际上是不同的对象

a = String.new("Hello")
b = "Hello"
a.object_id #=> 70295696460580
b.object_id #=> 70295696294220

答案 3 :(得分:1)

==检查内容是否相等。

equal?检查同等身份。

a = "hello"
b = "hello"

a == b # => true
a.equal?(b) # => false

在Ruby中,字符串文字不是不可变的,因此创建字符串并使用文字确实是相同的。在这两种情况下,每次评估表达式时,Ruby都会创建一个新的字符串实例。

因此两者都是相同的

10.times { String.new }
# is the same as
10.times { "" }

让我们验证这个

10.times { puts "".object_id }

打印10个不同的数字

70227981403600
70227981403520
70227981403460
...

为什么呢?字符串默认是可变的,因此每次在源代码中到达字符串文字时,Ruby都必须创建一个副本。即使这些文字在实践中通常很少被修改。

因此,Ruby程序通常会创建过多的短期字符串对象,这会给垃圾收集带来巨大压力。 Rails应用程序仅为一个请求创建500,000个短期字符串并不罕见,这是将Rails扩展到数百万甚至1亿用户的主要性能瓶颈之一。

解决Ruby 2.3引入的冻结字符串文字,其中所有字符串文字默认为不可变。由于这不是向后兼容的,因此选择使用pragma

# frozen_string_literal: true

让我们验证一下

# frozen_string_literal: true
10.times { puts "".object_id }

打印相同的数字10次

69898321746880
69898321746880
69898321746880
...

有趣的是,在哈希中设置密钥也会创建字符串的副本

str = "key"
hash = {}
hash[str] = true
puts str.object_id
puts hash.keys.first.object_id

打印两个不同的数字

70243164028580
70243132639660