除了这两种,有没有更好的方法可以在铁 rust 中铸造Vec<i8>
到Vec<u8>
?
- 通过映射和强制转换每个条目来创建副本
- 使用
std::transmute
(1)是缓慢的,(2)是"蜕变应该是绝对的最后手段"根据docs.
可能需要一点背景知识:我从不安全的gl::GetShaderInfoLog()调用中得到了Vec<i8>
,我想用String::from_utf8()
从这个字符向量中创建一个字符串.
除了这两种,有没有更好的方法可以在铁 rust 中铸造Vec<i8>
到Vec<u8>
?
std::transmute
(1)是缓慢的,(2)是"蜕变应该是绝对的最后手段"根据docs.
可能需要一点背景知识:我从不安全的gl::GetShaderInfoLog()调用中得到了Vec<i8>
,我想用String::from_utf8()
从这个字符向量中创建一个字符串.
其他答案为从Vec<i8>
创建字符串这一根本问题提供了极好的解决方案.为了回答提出的问题,从Vec<i8>
中的数据创建Vec<u8>
可以不用复制或转换向量.正如@trentcl所指出的,直接转换向量构成了未定义的行为,因为Vec
允许对不同类型有不同的布局.
在不复制矢量数据的情况下传输矢量数据的正确方法(尽管仍然需要使用unsafe
)是:
*mut i8
指针及其长度和容量Vec::from_raw_parts
构建一个新的向量,将指针强制转换为*mut u8
——这是不安全的部分,因为我们正在证明指针包含有效的初始化数据,并且其他对象没有使用它,等等.这不是UB,因为新Vec
从一开始就被赋予了正确类型的指针.代码(playground):
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]);
}