问题描述
是否有更好的方法在Rust中将 Vec
转换为 Vec
两个?
- 通过映射和转换每个条目来创建副本
- 使用
std :: transmute
(1)比较慢,(2)是 。。 p>
背景可能有点:我从不安全的Vec< i8> ://www.khronos.org/opengl/wiki/GLAPI/glGetShaderInfoLog rel = noreferrer> gl :: GetShaderInfoLog()调用,并希望使用<$ c从此字符向量创建一个字符串$ c> String :: from_utf8()。
其他答案为以下问题提供了出色的解决方案:从 Vec< i8>
创建字符串的基本问题。要回答所提出的问题,可以从 Vec< i8>
中的数据创建 Vec< u8>
而不复制或改变向量。正如@trentcl指出的那样,对向量进行直接转换会构成未定义的行为,因为允许 Vec
的不同类型具有不同的布局。
正确的方法(尽管仍然需要使用不安全
)来传输矢量数据而不进行复制的方法是:
- 获取指向向量中数据的
* mut i8
指针,以及其长度和容量 - 泄漏原始向量防止它释放数据
- 使用来构建一个新向量,并将其指针转换为
* mut u8
-这是不安全的部分,因为我们保证指针包含有效和初始化的数据,并且该指针未被其他对象使用,依此类推。
这不是UB,因为新的 Vec
被赋予了从一开始就选择正确的类型。代码():
fn vec_i8_into_u8(v:Vec< i8>)-> Vec< u8> {
//理想情况下,我们将使用Vec :: into_raw_parts,但是它很不稳定,
//因此我们必须手动执行:
//首先,确保v析构函数不会释放数据
// //超出范围时认为它拥有
let mut v = std :: mem :: ManuallyDrop :: new(v);
//然后,将现有的Vec
拆开,让p = v.as_mut_ptr();
let len = v.len();
let cap = v.capacity();
//最后,将数据采用新的Vec
不安全{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]);
}
Is there a better way to cast Vec<i8>
to Vec<u8>
in Rust except for these two?
- creating a copy by mapping and casting every entry
- using
std::transmute
The (1) is slow, the (2) is "transmute should be the absolute last resort" according to the docs.
A bit of background maybe: I'm getting a Vec<i8>
from the unsafe gl::GetShaderInfoLog() call and want to create a string from this vector of chars by using String::from_utf8()
.
The other answers provide excellent solutions for the underlying problem of creating a string from Vec<i8>
. To answer the question as posed, creating a Vec<u8>
from data in a Vec<i8>
can be done without copying or transmuting the vector. As pointed out by @trentcl, transmuting the vector directly constitutes undefined behavior because Vec
is allowed to have different layout for different types.
The correct (though still requiring the use of unsafe
) way to transfer a vector's data without copying it is:
- obtain the
*mut i8
pointer to the data in the vector, along with its length and capacity - leak the original vector to prevent it from freeing the data
- use
Vec::from_raw_parts
to build a new vector, giving it the pointer cast to*mut u8
- this is the unsafe part, because we are vouching that the pointer contains valid and initialized data, and that it is not in use by other objects, and so on.
This is not UB because the new Vec
is given the pointer of the correct type from the start. Code (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]);
}
这篇关于将i8的向量转换为Rust中u8的向量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!