如何在编译时检查切片是否具有特定大小?

Jon*_*ght 2 rust

我想在编译时检查实现中使用的切片是否From具有特定大小。

游乐场

#[derive(Debug)]
struct Pixel {
    r: u8,
    g: u8,
    b: u8,
}

impl From<&[u8]> for Pixel {
    fn from(arr: &[u8]) -> Pixel {
        Pixel {
            r: arr[0],
            g: arr[1],
            b: arr[2],
        }
    }
}

fn main() {
    println!("Hello, world!");

    let arr: [u8; 9] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    let pixels: Vec<Pixel> = arr.chunks_exact(3).map(Pixel::from).collect();
    println!("{:.?}", pixels);
}
Run Code Online (Sandbox Code Playgroud)

这并不像我想要的那么具体。我想尽可能清楚地检查arr传递给is 3 个元素(在编译时)。Pixel::from<&[u8]>()

想到了assert!(arr.len()==3),但这在运行时检查。

所以我想也许我可以通过( Playground )进行转换:

impl From<[u8; 3]> for Pixel {
    fn from(arr: [u8; 3]) -> Pixel {
        Pixel {
            r: arr[0],
            g: arr[1],
            b: arr[2],
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但这会导致:

error[E0277]: the trait bound `Pixel: From<&[u8]>` is not satisfied
   --> src/main.rs:22:30
    |
22  |       let pixels: Vec<Pixel> = arr.chunks_exact(3).map(Pixel::from).collect();
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<&[u8]>` is not implemented for `Pixel`
    |
    = help: the following implementations were found:
              <Pixel as From<[u8; 3]>>

error[E0277]: the trait bound `Pixel: From<&[u8]>` is not satisfied
  --> src/main.rs:22:54
   |
22 |     let pixels: Vec<Pixel> = arr.chunks_exact(3).map(Pixel::from).collect();
   |                                                      ^^^^^^^^^^^ the trait `From<&[u8]>` is not implemented for `Pixel`
   |
   = help: the following implementations were found:
             <Pixel as From<[u8; 3]>>
   = note: required by `from`

error[E0277]: the trait bound `Pixel: From<&[u8]>` is not satisfied
   --> src/main.rs:22:30
    |
22  |       let pixels: Vec<Pixel> = arr.chunks_exact(3).map(Pixel::from).collect();
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<&[u8]>` is not implemented for `Pixel`
    |
    = help: the following implementations were found:
              <Pixel as From<[u8; 3]>>
Run Code Online (Sandbox Code Playgroud)

同样我尝试过From<&[u8; 3]>但结果相同。

有没有办法实现特定大小的切片?

这不是如何将切片转换为数组引用?由于这个问题具体涉及在编译时检查而不影响运行时性能,因此它不会强制转换&[u8]&[u8; 3]简单地在编译时检查&[u8]是否有 3 个元素(可以通过 using 来完成&[u8; 3])。上述问题的所有答案都会产生运行时影响,除了我相信这个答案中的这种方法(像这样应用),但这根本不检查切片是否具有适当的长度。这个问题并不是专门关于能够使用,Pixel::from<[u8;3]>而是关于在编译时一般检查长度,这些答案都没有提供或与之相关。

She*_*ter 6

您不能在编译时执行此操作,因为切片长度在编译时未知。这是切片存在的一个重要原因。当编译时长度已知时,那就是一个数组。

也可以看看:


相反,我会写出易错和绝对正确的转换:

use std::array::TryFromSliceError;
use std::convert::TryFrom;

#[derive(Debug)]
struct Pixel {
    r: u8,
    g: u8,
    b: u8,
}

impl TryFrom<&[u8]> for Pixel {
    type Error = TryFromSliceError;

    fn try_from(arr: &[u8]) -> Result<Self, Self::Error> {
        <&[u8; 3]>::try_from(arr).map(Self::from)
    }
}

impl From<&[u8; 3]> for Pixel {
    fn from(arr: &[u8; 3]) -> Self {
        Self::from(*arr)
    }
}

impl From<[u8; 3]> for Pixel {
    fn from(arr: [u8; 3]) -> Self {
        Pixel {
            r: arr[0],
            g: arr[1],
            b: arr[2],
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以从数组进行转换,允许出现编译时错误,或者当您有一个切片并且在编译时不知道长度时,您可以尝试转换并出现运行时错误。

将来,您可以使用诸如slice::array_chunks将切片转换为数组迭代器之类的方法。然而,仍然存在切片长度不正确(太长或太短)的情况,您必须以某种方式处理。