对于大多数程序,最好在内部使用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
是未大小的字符串类型(可以定义为struct Utf16Str([u16])
)。这将避免在访问字符串时跟随两个指针,但我不知道如何实例化具有unsize类型的Rc
。
考虑到上述要求,仅仅使用rust编码是非常不方便的,因为它将所有非utf -8编码视为u8
的向量。
另外,我不确定使用std库是否会对我有所帮助。我查看了Utf16Units
,它只是一个迭代器,而不是一个合适的字符串类型。(另外,我知道OsString
没有帮助-我不在Windows上,它甚至没有实现Index<usize>
)
由于这里有多个问题,我将尝试分别回答:
我认为你需要的类型是[u16]
和Vec<u16>
。
默认的字符串类型 类似地,您可以使用 但是正如您在问题中注意到的,JavaScript字符串可以包含未配对的代理。这是因为JavaScript字符串不是严格的UTF-16,它们实际上是 没有不变量需要维护,我不认为包装类型有那么大的用处。 rust-encoding支持基于字节的UTF-16-LE和UTF-16-BE。您可能需要基于 获取 如果你要使用原始内存分配,最好使用你自己的类型,这样你就可以使用它的私有字段。卷须是这样做的:https://github.com/servo/tendril/blob/master/src/buf32.rs 或者,如果你愿意承担额外的间接成本,str
和String
是[u8]
和Vec<u8>
的包装(严格来说,str
不是原始的,但足够接近)。使用单独的类型是为了保持底层字节在UTF-8中格式良好的不变性。Utf16Str
和Utf16String
类型包裹[u16]
和Vec<u16>
,以保留在UTF-16中格式良好的不变量,即没有未配对的代理。u16
的任意序列,没有额外的不变量。u16
的UTF-16。std::str::Utf16Units
确实不是字符串类型。它是一个由str::utf16_units()
方法返回的迭代器,它将Rust字符串转换为UTF-16(不是LE或BE)。例如,您可以在该迭代器上使用.collect()
来获得Vec<u16>
。Rc<[u16]>
的唯一安全方法是强制Rc<[u16; N]>
,其大小在编译时已知,这显然是不切实际的。我不推荐不安全的方法:分配内存,给它写一个头,希望能匹配RcBox
的内存表示,然后转换。Rc<Vec<u16>>
是安全的,更容易。