如何将不可变视图(切片?)作为八位字节借给矢量?

时间:2014-11-03 13:03:52

标签: type-conversion rust

我正在尝试使用UDP通过网络发送32位浮点数向量。 UdpSocket.send_to(buf, dst)方法接受一个8位uint切片。我想把它作为&[u8]传递给它。我该如何做到这一点?我没有从API中找到任何相关的转换方法。

在这种情况下无需关心字节顺序。爱好。

2 个答案:

答案 0 :(得分:8)

首先,这些操作本质上是不安全的,因此如果没有unsafe阻止就无法完成。

切片是一对(pointer, length),虽然您可以将原始指针转换为某种类型作为指向另一种类型的原始指针,但您还需要调整长度以使结果切片有效。这可以这样做:

use std::raw::Slice;
use std::mem;

fn main() {
    let floats: Vec<f32> = vec![0.1, 2.3, 4.5, 6.7];
    let floats: &[f32] = floats.as_slice();

    let raw_floats: Slice<f32> = unsafe { mem::transmute(floats) };
    let raw_bytes: Slice<u8> = Slice {
        data: raw_floats.data as *const u8,
        len: raw_floats.len * mem::size_of::<f32>()
    };

    let bytes: &[u8] = unsafe { mem::transmute(raw_bytes) };

    println!("{}", bytes);
}

(试试here

当然,上面的大多数类型注释都是为了清晰起见。

您应该特别注意确保获得的&[u8]切片不会超过其原始数据所有者(在这种情况下为向量)。如果你只是通过调用堆栈传递这个片段(你的用例 - 通过网络发送数据 - 似乎是这样),那么你没关系;如果你需要从函数中返回这样的切片,你需要注意一生,尽管Rust类型/生命周期推断足够高,使它们几乎不可见。例如,从&[T]转换为&[u8]的通用方法可能如下所示:

use std::raw::Slice;
use std::mem;

fn view_as_bytes<'a, T: Copy>(items: &'a [T]) -> &'a [u8] {  // '
    let raw_items: Slice<T> = unsafe { mem::transmute(items) };
    let raw_bytes = Slice {
        data: raw_items.data as *const u8,
        len: raw_items.len * mem::size_of::<T>()
    };
    let bytes: &[u8] = unsafe { mem::transmute(raw_bytes) };
    bytes
}

fn main() {
    let floats: Vec<f32> = vec![0.1, 2.3, 4.5, 6.7];
    let bytes = view_as_bytes(floats.as_slice());

    println!("{}", bytes);
}

(试试here

为了清楚起见,我添加了生命周期参数'a,但由于生命周期的省略,可以安全地省略它。

但是,如果您的数据是在函数内创建的,则不应从此函数返回任何切片。 transmute()足够强大,但最终只能导致段错误。

答案 1 :(得分:1)

要将单个浮点数转换为字节表示形式,请使用mem::transmute

let floaty_stuff = 234.5f32;
let bytes: [u8, ..4] = unsafe{ std::mem::transmute(floaty_stuff) };
let slice = bytes.as_slice(); // this is &[u8]

要为矢量执行此操作,您只需.iter().map(|f| mem::transmute::<[u8 ..4], f32>(f).as_slice() )