英文:
How can a function be generic over a struct and uints in Rust, using methods defined for both?
问题
我有一个名为S
的结构体定义
struct S {
pub inner_state: [u8; N],
}
其中包含一些实现在设置边界之间旋转位的方法(即,我可以旋转最后5位,这是我需要做的)。
我还有一堆类似于的函数
pub fn compute_stuff(state: OtherStruct<S>) {
do_bit_wise_operations!();
}
现在,由于结构体S
实现了这些函数内部使用的所有方法,我想将这些函数泛化为T
,其中T
可以是无符号整数或结构体S
。
我尝试将函数签名更改为
pub fn compute_stuff<T>(state: OtherStruct<T>)
where T: std::ops::BitAnd<Output = T> + [...]
{
do_bit_wise_operations!();
}
但我遇到了障碍。我使用了leading_zeros()
方法,该方法对结构体S
存在,但我似乎找不到应该如何告诉编译器它的存在。另外,这样写会变得有点冗长,有没有一种方法可以为这个特定的T
创建别名?
我还尝试创建一个名为BitOperations
的特性,并为S
和无符号整数实现它,但我不太明白它如何帮助我解决这个问题。
英文:
So I have a struct S
defined
struct S {
pub inner_state: [u8; N],
}
with some methods that implement rotating a bit between set bounds (i.e. I can rotate bits for the last 5 bits, which I need to do.)
I also have a bunch of function like
pub fn compute_stuff(state: OtherStruct<S>) {
do_bit_wise_operations!();
}
Now, since the struct S
implements all the methods that are used inside these functions, I would like to make these function generics over T
, where T
can be either an uint or the struct S
.
I tried changing the function signature to
pub fn compute_stuff<T>(state: OtherStruct<T>)
where T: std::ops::BitAnd<Output = T> + [...]
{
do_bit_wise_operations!();
}
but I get to a road block. I use the leading_zeros()
method that does exist for the struct S
, but I can't seem to find how I should tell the compiler that it exists. Also, this get kinda long to write, is there a way to alias this specific T
?
I also tried creating a trait BitOperations
and impl it for S
and the uints, but I don't really understand how it could help me solve this problem.
答案1
得分: 4
创建一个特性确实有效。首先,创建特性。由于您希望它增强现有特性的行为,您可以将其设置为BitAnd
的子特性。
use std::ops::BitAnd;
pub trait BitOps: BitAnd<Output = Self> + Sized {
fn leading_zeros(self) -> u32;
}
由于它使用了self
的值,所以需要Sized
。
然后,您可以为您的类型实现特性。
// 为原始类型实现(可以使用宏来为多个原始类型执行此操作)
impl BitOps for i32 {
fn leading_zeros(self) -> u32 {
self.leading_zeros()
}
}
impl BitAnd for S {
type Output = Self;
fn bitand(mut self, other: Self) -> Self {
for (a, b) in self.inner_state.iter_mut().zip(other.inner_state) {
*a = *a & b;
}
self
}
}
// 为S实现特性
impl BitOps for S {
fn leading_zeros(self) -> u32 {
let mut zeros = 0;
for byte in self.inner_state {
if byte == 0 {
zeros += 8;
} else {
zeros += byte.leading_zeros();
break;
}
}
zeros
}
}
然后,您可以使用它。
pub fn compute_stuff<T>(state: T) where T: BitOps + Copy {
let _leading_zeros = state.leading_zeros();
let _bit_and = state & state;
}
这就是num-traits库的工作方式,但具有更多的特性和类型。它没有这么具体的特性,但PrimInt
是BitAnd
的子特性,如果您想扩展功能,可能会有用。
英文:
Creating a trait does work. First, create the trait. Since you want it to augment the behavior of an existing trait, you can make it a subtrait of BitAnd
.
use std::ops::BitAnd;
pub trait BitOps: BitAnd<Output = Self> + Sized {
fn leading_zeros(self) -> u32;
}
Sized
is necessary since it takes self
by value.
Then you can implement the trait for your types.
// Implemented for a primitive (a macro is useful to do this for many primitives)
impl BitOps for i32 {
fn leading_zeros(self) -> u32 {
self.leading_zeros()
}
}
impl BitAnd for S {
type Output = Self;
fn bitand(mut self, other: Self) -> Self {
for (a, b) in self.inner_state.iter_mut().zip(other.inner_state) {
*a = *a & b;
}
self
}
}
// Implemented for S
impl BitOps for S {
fn leading_zeros(self) -> u32 {
let mut zeros = 0;
for byte in self.inner_state {
if byte == 0 {
zeros += 8;
} else {
zeros += byte.leading_zeros();
break;
}
}
zeros
}
}
And then you can use it.
pub fn compute_stuff<T>(state: T) where T: BitOps + Copy {
let _leading_zeros = state.leading_zeros();
let _bit_and = state & state;
}
This is how the num-traits library works, but with more traits and types. It doesn't have any traits that are this specific, but PrimInt
is a subtrait of BitAnd
and could be useful if you want to expand your functionality.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论