当前位置: 首页 > 知识库问答 >
问题:

无法创建将字节片转换为整数的泛型函数,因为编译时大小未知

云骏奇
2023-03-14

我试图创建一个通用函数,将字节片转换为整数。

fn i_from_slice<T>(slice: &[u8]) -> Option<T>
where
    T: Sized,
{
    match slice.len() {
        std::mem::size_of::<T>() => {
            let mut buf = [0; std::mem::size_of::<T>()];
            buf.copy_from_slice(slice);
            Some(unsafe { std::mem::transmute_copy(&buf) })
        }
        _ => None,
    }
}

Rust不会让我这么做的:

error[E0532]: expected tuple struct/variant, found function `std::mem::size_of`
 --> src/lib.rs:6:9
  |
6 |         std::mem::size_of::<T>() => {
  |         ^^^^^^^^^^^^^^^^^^^^^^ not a tuple struct/variant

error[E0277]: the size for values of type `T` cannot be known at compilation time
 --> src/lib.rs:7:31
  |
7 |             let mut buf = [0; std::mem::size_of::<T>()];
  |                               ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
  |
  = help: the trait `std::marker::Sized` is not implemented for `T`
  = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
  = help: consider adding a `where T: std::marker::Sized` bound
  = note: required by `std::mem::size_of`

有没有一种方法可以静态地知道T的大小?

共有3个答案

茅才
2023-03-14

有没有一种方法可以静态地知道T的大小?

是的,你知道编译时的大小。但是大小可以变化,并且不是一个常数。不使用固定大小的数组,您可以使用一个向量,它是一个连续的可增长数组。

此外,Size是一个选择退出标记特征。所有类型参数都有一个隐式的Size绑定。您不需要拼出这个事实。

你需要一个火柴护臂来使用模式匹配,但是这里使用if-else表达式更简单。

总之,这是有效的:

fn i_from_slice<T>(slice: &[u8]) -> Option<T> {
    let n = std::mem::size_of::<T>();
    if slice.len() == n {
        let mut buf = vec![0; n];
        buf.copy_from_slice(slice);
        Some(unsafe { std::mem::transmute_copy(&buf) })
    } else {
        None
    }
}
李和昶
2023-03-14

您不需要中间缓冲区,可以直接在输入片上调用transmute_copy。此外,正如@BenjaminLindley在评论中指出的那样,您需要确保从切片中的第一项而不是切片本身的胖指针转换:

fn i_from_slice<T>(slice: &[u8]) -> Option<T> {
    if slice.len() == std::mem::size_of::<T>() {
        Some(unsafe { std::mem::transmute_copy(&slice[0]) })
    } else {
        None
    }
}
赫连泰宁
2023-03-14

如果您的T是一个整数,您不需要任何不安全的代码,因为有from_ne_bytes

如果你绝对想要一个泛型函数,你可以添加一个特征:

use std::convert::TryInto;

trait FromBytes: Sized {
    fn from_ne_bytes_(bytes: &[u8]) -> Option<Self>;
}

impl FromBytes for i32 {
    fn from_ne_bytes_(bytes: &[u8]) -> Option<Self> {
        bytes.try_into().map(i32::from_ne_bytes).ok()
    }
}

// Etc. for the other numeric types.

fn main() {
    let i1: i32 = i_from_slice(&[1, 2, 3, 4]).unwrap();
    let i2 = i32::from_ne_bytes_(&[1, 2, 3, 4]).unwrap();

    assert_eq!(i1, i2);
}

// This `unsafe` usage is invalid, but copied from the original post
// to compare the result with my implementation.
fn i_from_slice<T>(slice: &[u8]) -> Option<T> {
    if slice.len() == std::mem::size_of::<T>() {
        Some(unsafe { std::mem::transmute_copy(&slice[0]) })
    } else {
        None
    }
}
 类似资料:
  • 问题内容: 如何将(大字节序)可变大小的二进制字节数组转换为(无符号)整数/长整数?例如,代表4404 现在,我正在使用 它虽然很小,但有点可读,但可能效率不高。有没有更好(更明显)的方法? 问题答案: 传统上,Python对于“大尾数C布局中的数字”用处不大,而对于C来说则用不了太多。(如果要处理2字节,4字节或8字节的数字,那么答案就是) 但是足够多的人厌倦了没有一种明显的方法可以做到这一点,

  • 问题内容: 我有一个接收a的函数,但是我所拥有的a是进行此转换的最佳方法是什么? 我想我可以走很长一段路,然后将其放入字符串并放入字节中,但这听起来很难看,而且我认为还有更好的方法可以做到。 问题答案: 我同意Brainstorm的方法:假设您要传递机器友好的二进制表示形式,请使用该库。OP建议可能会有一些开销。纵观源的实施,我看到它做了一些运行时的决策最大的灵活性。 对?Write()接受一个非

  • 问题内容: 将转换为的快速方法是什么? 例如 问题答案: 看看ByteBuffer类。 设置字节顺序保证了,,和。 或者,你可以手动执行以下操作: 该班是专为尽管这样的脏手任务。实际上,私有定义了以下辅助方法:

  • 我试图通过API发送数据,但得到了类型错误:无法将字节转换为str。我理解这意味着我需要将部分代码转换为字节,但我不确定如何执行。我尝试在前面添加b或使用字节(“数据”),但可能将它们放在了错误的区域。 这是问题行: 我不确定什么和如何转换为字节。

  • 问题内容: 例如输入:(类型:) 转换示例:(类型:的切片) 问题答案: 除了mhutter的答案外,还请注意您的输入看起来像一个JSON数组(也许是来自JSON文本?)。 如果您这样处理,则可以将其内容编组为一个切片。直接解析其中的数字并不会更快(因为该包使用了反射),但是它肯定更简单: 输出(在Go Playground上尝试):

  • 问题内容: 我想执行转换而不求助于某些依赖于实现的技巧。有小费吗? 问题答案: 您需要知道字节的字节序。 假设(例如@ WhiteFang34),其是一个长度为4的,然后… … 大端: 小端: