在 Rust 中将 i8 的向量转换为 u8 的向量?

Ale*_*der 19 string casting vector rust

有没有更好的方式来投Vec<i8>Vec<u8>鲁斯特除了这两个人?

  1. 通过映射和投射每个条目来创建副本
  2. 使用 std::transmute

根据文档,(1) 很慢,(2) 是“转化应该是绝对的最后手段” 。

可能有一点背景知识:我Vec<i8>从不安全的gl::GetShaderInfoLog()调用中得到了一个,并希望通过使用String::from_utf8().

use*_*342 18

其他答案为从Vec<i8>. 要回答提出的问题,可以在不复制或转换向量的情况下Vec<u8>从a 中的数据创建 a Vec<i8>。正如@trentcl 所指出的,直接转换向量构成未定义的行为,因为Vec允许对不同的类型有不同的布局。

unsafe传输向量数据而不复制它的正确(尽管仍然需要使用)方法是:

  • 获取*mut i8指向向量中数据的指针,以及它的长度和容量
  • 泄漏原始向量以防止其释放数据
  • 用于Vec::from_raw_parts构建一个新的向量,给它一个*mut u8强制转换的指针——这是不安全的部分,因为我们保证指针包含有效和初始化的数据,并且它没有被其他对象使用,等等。

这不是 UB,因为 newVec从一开始就被赋予了正确类型的指针。代码(游乐场):

fn vec_i8_into_u8(v: Vec<i8>) -> Vec<u8> {
    // ideally we'd use Vec::into_raw_parts, but it's unstable,
    // so we have to do it manually:

    // first, make sure v's destructor doesn't free the data
    // it thinks it owns when it goes out of scope
    let mut v = std::mem::ManuallyDrop::new(v);

    // then, pick apart the existing Vec
    let p = v.as_mut_ptr();
    let len = v.len();
    let cap = v.capacity();
    
    // finally, adopt the data into a new Vec
    unsafe { Vec::from_raw_parts(p as *mut u8, len, cap) }
}

fn main() {
    let v = vec![-1i8, 2, 3];
    assert!(vec_i8_into_u8(v) == vec![255u8, 2, 3]);
}
Run Code Online (Sandbox Code Playgroud)

  • 只是因为 `Vec&lt;T&gt;` 的表示可能依赖于 `T`。这不太可能,但这是允许的。我承认我很难想象在什么情况下这会是一个有用的东西。 (2认同)

tre*_*tcl 11

transmuteon aVec总是 100% 错误,导致未定义的行为,因为Vec未指定的布局。但是,正如您链接的页面也提到的,您可以使用原始指针并Vec::from_raw_parts正确执行此操作。user4815162342 的回答显示了如何。

std::mem::transmute是 Rust 标准库中唯一一个其文档主要由如何使用它的建议组成的项目。按照你的意愿去做。)

但是,在这种情况下,from_raw_parts也是不必要的。在 Rust 中处理 C 字符串的最佳方法是使用std::ffi,CStr和 中的包装器CString。可能有更好的方法可以将其应用到您的实际代码中,但您可以使用以下一种方法将CStraVec<c_char>作为 a借用&str

const BUF_SIZE: usize = 1000;
let mut info_log: Vec<c_char> = vec![0; BUF_SIZE];
let mut len: usize;
unsafe {
    gl::GetShaderInfoLog(shader, BUF_SIZE, &mut len, info_log.as_mut_ptr());
}
let log = Cstr::from_bytes_with_nul(info_log[..len + 1])
    .expect("Slice must be nul terminated and contain no nul bytes")
    .to_str()
    .expect("Slice must be valid UTF-8 text");
Run Code Online (Sandbox Code Playgroud)

请注意,unsafe除了调用 FFI 函数外,没有其他代码;您还可以使用with_capacity+ set_len(如在wasmup 的回答中)跳过Vec将 1000 个零初始化,并用于from_bytes_with_nul_unchecked跳过检查返回字符串的有效性。