如何使 Rust 函数在 u8 切片上通用 | u32?

cur*_*nii 0 generics traits slice rust

我正在努力移植一个具有以下类型别名和函数的 Typescript 库:

type GlkTypedArray = Uint8Array | Uint32Array
get_buffer(buf: GlkTypedArray): number
Run Code Online (Sandbox Code Playgroud)

非常简单,它接受 aUint8Array或 a Uint32Array

u8我现在尝试通过仅为and定义的特征在 Rust 中做同样的事情u32

trait GlkInt: Sized {}
impl GlkInt for u8 {}
impl GlkInt for u32 {}

fn get_buffer(buf: &mut [dyn GlkInt]) -> u32;
Run Code Online (Sandbox Code Playgroud)

但不幸的是,它不允许这样做,说该特质不是Sized,尽管我认为特质定义意味着它会是。

error[E0277]: the size for values of type `dyn misc::GlkInt` cannot be known at compilation time
  --> remglk/src/glkapi/streams.rs:18:29
   |
18 |     fn get_buffer(buf: &mut [dyn GlkInt]) -> u32;
   |                             ^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `dyn misc::GlkInt`
   = note: slice and array elements must have `Sized` type

error[E0038]: the trait `misc::GlkInt` cannot be made into an object
  --> remglk/src/glkapi/streams.rs:18:30
   |
18 |     fn get_buffer(buf: &mut [dyn GlkInt]) -> u32;
   |                              ^^^^^^^^^^ `misc::GlkInt` cannot be made into an object
   |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
  --> remglk/src/common/misc.rs:13:19
   |
13 | pub trait GlkInt: Sized {}
   |           ------  ^^^^^ ...because it requires `Self: Sized`
   |           |
   |           this trait cannot be made into an object...
Run Code Online (Sandbox Code Playgroud)

我是否需要做其他事情,或者整个方法不起作用?我还能尝试什么?

caf*_*e25 5

需要在编译时知道数组/切片元素的大小,以便编译器可以计算两个项目之间的距离以进行索引。a 的dyn GlkInt宽度为 1 或 4 个字节,因此无法知道其大小。

您可以只使用泛型类型进行静态调度,在这种情况下您可能希望在泛型上需要更多特征(From<u8>Into<u32>想到):

trait GlkInt {}
impl GlkInt for u8 {}
impl GlkInt for u32 {}

fn get_buffer<T: GlkInt>(buf: &mut [T]) -> u32 {
    0
}
Run Code Online (Sandbox Code Playgroud)

或者使用枚举并自己实现不同的代码路径。

use GlkSlice::*;
enum GlkSlice<'a> {
    U8(&'a mut [u8]),
    U32(&'a mut [u32]),
}

fn get_buffer(buf: GlkSlice<'_>) -> u32 {
    match buf {
        U8(buf) => buf[0] as u32,
        U32(buf) => buf[0],
    }
}
Run Code Online (Sandbox Code Playgroud)