在引入可选的冻结字符串的Ruby 2.3之前,可以使用铲运算符("<<",别名为" concat")附加字符串。但是,铲子操作符不仅仅是附加一个字符串,而是将数字视为代码点并perform various checks for the current and appending string encodings
$ x = "hello"
$ x << 33 # or: x << 0b111000 , x << 0x111, etc
#=> "hello!"
通过设置可选的#frozen_string_literal配置选项,字符串不再可变,因此无法使用铲子操作符,这会改变它所调用的对象。但是,通过重新分配变量来创建字符串似乎需要大量的编码工作是显式的,而不是隐式的
$ x = "hello"
$ x += 33
#=> TypeError: no implicit conversion of Integer into String
我经常通过执行以下操作来解决问题:
$ x = "hello"
$ x += [33].pack("U")
#=> hello!
如列出的under the directives for Array.pack,pack方法需要了解很多输入。到目前为止,我发现在用可变重新分配替换可变字符串连接(&#34; x&lt;&lt; y&#34;)&#34; x + = y&#34;时,这是一种痛苦。在现有的代码库中。
作为参考,我尝试更新someone's existing project to use immutable strings,但我并不总是清楚地知道字符串编码是什么。字节在8位,16位等之间变化很大,需要打包(&#39; n&#39;),打包(&#39; c&#39;),打包(&#39; U&#39; )等等。
虽然我认为最好的答案是在字符串编码中明确表示,以后可以避免潜在的错误,因为我可以访问这两个对象,但是不可变性本身应该要求现在需要更多的信息。
是否可以轻松替换铲运算符,它可以对现有和附加字符串提供相同类型的编码推断?理想情况下,与#34; x.concat(y)&#34;相同的C代码。但是没有进行到位更改,利用编码检查相同的编码检查而不违反不变性?
谢谢!
答案 0 :(得分:0)
为了连接两个字符串,它们需要采用兼容的编码。 LosingPlace
将尝试查找与两个操作数兼容的编码,并将第一个操作数转换为该编码。
String#<<
请注意,在最后一行中a = "a".encode('ascii-8bit')
a.encoding #=> #<Encoding:ASCII-8BIT>
b = "b"
b.encoding #=> #<Encoding:UTF-8>
a << b #=> "ab"
a.encoding #=> #<Encoding:ASCII-8BIT>
c = "ø"
c.encoding #=> #<Encoding:UTF-8>
a << c #=> "abø"
a.encoding #=> #<Encoding:UTF-8>
的编码如何更改以适应a
编码中不存在的字符。
如果右参数是数字,则此数字将被解释为当前编码中的代码点。如果该编码为ASCII-8BIT
,则该数字可以从ASCII-8BIT
转到0
;如果编码为255
,则最高可达UTF-8
(1114111
);其他编码有不同的范围。
要使用不可变字符串复制相同的功能,理想情况下,您可以这样做:
0x10FFFF
注意:最初我认为你有适当编码的原始字节,所以我建议x += y.encode(x.encoding) # instead of destructive `x << y`
x += 33.chr(x.encoding) # instead of destructive `x << 33`
而不是String#force_encoding
,但如果我理解你的意思,这实际上会给你错误的结果。