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