dar*_*que 7 string utf-16 rust
对于大多数程序,最好在内部使用UTF-8,并在必要时转换为其他编码.但在我的情况下,我想编写一个Javascript解释器,并且只存储UTF-16字符串(或数组u16
)更简单,因为
我需要单独处理16位代码单元(这通常是一个坏主意,但Javascript需要这个).这意味着我需要它来实现Index<usize>
.
我需要存储不成对代理人,即,畸形UTF-16的字符串(正因为如此,ECMAScript的字符串在技术上定义为阵列u16
,其通常代表UTF-16的字符串).有一个名为WTF-8的编码用于存储UTF-8中不成对的代理,但我不想使用这样的东西.
我希望拥有通常拥有/借用的类型(如String
/ str
和CString
/ CStr
)以及所有或最常用的方法.我不想滚动自己的字符串类型(如果我可以避免).
此外,我的字符串将始终是不可变的,位于Rc
包含指向所有字符串的弱指针的数据结构后面(并实现字符串实习).这可能是相关的:也许最好是Rc<Utf16Str>
作为字符串类型,其中Utf16Str
是未定义的字符串类型(可以定义为just struct Utf16Str([u16])
).这样可以避免在访问字符串时遵循两个指针,但我不知道如何Rc
使用unsized类型实例化.
鉴于上述要求,仅使用防锈编码非常不方便,因为它将所有非UTF-8编码视为矢量u8
.
另外,我不确定使用std库是否可以帮助我.我调查了Utf16Units
它,它只是一个迭代器,而不是一个正确的字符串类型.(另外,我知道OsString
没有帮助 - 我不在Windows上,甚至没有实现Index<usize>
)
由于这里有多个问题,我将尝试分别回答:
我认为您想要的类型是[u16]
和Vec<u16>
。
默认的字符串类型str
和String
是环绕[u8]
和的包装Vec<u8>
(从技术上讲,str
它不是原始的,但足够接近)。具有单独类型的目的是要保持不变,即底层字节在UTF-8中格式正确。
类似地,您可能拥有Utf16Str
和Utf16String
包装类型,[u16]
并且Vec<u16>
保留了格式良好的UTF-16不变式,即没有不成对的代理。
但是,正如您在问题中指出的那样,JavaScript字符串可以包含未配对的代理。这是因为JavaScript字符串严格来说不是UTF-16,它们实际上是任意序列,u16
没有附加的不变性。
无需维护不变性,我认为包装器类型并没有那么有用。
锈编码支持基于字节的UTF-16-LE和UTF-16-BE。您可能需要基于的UTF-16 u16
。
std::str::Utf16Units
确实不是字符串类型。它是由str::utf16_units()
将Rust字符串转换为UTF-16(不是LE或BE)的方法返回的迭代器。您可以.collect()
在该迭代器上使用以获取一个Vec<u16>
示例。
唯一安全的获取方法是在编译时Rc<[u16]>
强制确定Rc<[u16; N]>
其大小,这显然是不切实际的。我不建议这种不安全的方法:分配内存,向其中写入一个希望与的内存表示形式匹配的标头RcBox
,然后进行转换。
如果要使用原始内存分配,最好使用自己的类型,以便可以使用其私有字段。Tendril会这样做:https://github.com/servo/tendril/blob/master/src/buf32.rs
或者,如果您愿意承担额外的间接费用,那将Rc<Vec<u16>>
是安全且容易得多的。