如何将Rust字符串转换为UTF-16?

14
编辑注:此代码示例来自 Rust 1.0 之前的版本,不是有效的 Rust 1.0 代码,但答案仍包含有价值的信息。
我想将一个字符串字面量传递给 Windows API。许多 Windows 函数使用 UTF-16 作为字符串编码,而 Rust 的本地字符串是 UTF-8。
我知道 Rust 有utf16_units()来生成一个UTF-16字符迭代器,但我不知道如何使用该函数生成以零结尾的UTF-16字符串。
我像这样生成UTF-16字符串,但我相信有更好的方法来生成它:
extern "system" {
    pub fn MessageBoxW(hWnd: int, lpText: *const u16, lpCaption: *const u16, uType: uint) -> int;
}

pub fn main() {
    let s1 = [
        'H' as u16, 'e' as u16, 'l' as u16, 'l' as u16, 'o' as u16, 0 as u16,
    ];
    unsafe {
        MessageBoxW(0, s1.as_ptr(), 0 as *const u16, 0);
    }
}
4个回答

26

Rust 1.8+

str::encode_utf16 是 UTF-16 值的稳定迭代器。

你只需要在该迭代器上使用 collect() 构建一个 Vec<u16>,然后在该向量上调用 push(0)

pub fn main() {
    let s = "Hello";

    let mut v: Vec<u16> = s.encode_utf16().collect();
    v.push(0);
}

Rust 1.0+

str::utf16_units() / str::encode_utf16未稳定。替代方案是切换到nightly(如果您正在编写程序而不是库,则是可行的选择),或者使用像encoding这样的外部crate:

extern crate encoding;

use std::slice;

use encoding::all::UTF_16LE;
use encoding::{Encoding, EncoderTrap};

fn main() {
    let s = "Hello";

    let mut v: Vec<u8> = UTF_16LE.encode(s, EncoderTrap::Strict).unwrap();
    v.push(0); v.push(0);
    let s: &[u16] = unsafe { slice::from_raw_parts(v.as_ptr() as *const _, v.len()/2) };
    println!("{:?}", s);
}

(或者你可以使用from_raw_parts_mut,如果您想要一个&mut [u16]。)

但是,在这个特定的示例中,您必须注意字节序,因为UTF_16LE编码给出了一个表示小端字节序的字节向量,而from_raw_parts技巧允许您将字节向量“视为”平台字节序的切片,这也可能是大端。如果您想要完全可移植性,使用像byteorder这样的crate可能会有所帮助。

Reddit上的这个讨论也可能会有所帮助。


哇,那个有效!谢谢。之前我用了 let mut v = s.utf16_units().collect::<u16>(); 但是代码无法编译通过。 - Gigih Aji Ibrahim
1
@GigihAjiIbrahim,编译失败是因为collect()的类型参数应该是目标集合类型,而不是元素类型。collect::<Vec<u16>>()也可以工作。 - Vladimir Matveev

5

Rust 1.46+

对于静态的UTF-16字符串,可以使用utf16_litcrate中提供的宏来在编译时轻松实现:

use utf16_lit::utf16_null;

fn main() {
    let s = &utf16_null!("Hello");
    println!("{:?}", s);
}

2

1
我认为在当前的 Rust 版本中,这是处理 Windows API 最好的答案。从未想到我九年前的问题仍然有用。 - Gigih Aji Ibrahim

0

WinSafe 的 crate 专门为此提供了 WString 类型:

let my_str = WString::from_str("Some text");

unsafe {
    SomeNativeFunctionW( my_str.as_ptr() );
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接