我有一个类型Indexer
,它可以Forward
(+1) 或Backward
(-1)。在 C++ 中:
enum Direction {
Forward,
Backward
};
template <Direction Dir>
struct Indexer {
static constexpr int delta = (Dir == Forward ? 1 : -1);
};
void foo() {
Indexer<Forward> f;
}
这是我在 Rust 中实现的最好方法:
use std::marker::PhantomData;
#[derive(Copy, Clone)]
pub struct Forward;
#[derive(Copy, Clone)]
pub struct Backward;
pub trait Direction: Copy {
const DELTA: i32;
}
impl Direction for Forward {
const DELTA: i32 = 1;
}
impl Direction for Backward {
const DELTA: i32 = -1;
}
#[derive(Copy, Clone)]
pub struct Indexer<Dir: Direction> {
pd: PhantomData<Dir>,
}
impl<Dir: Direction> Indexer<Dir> {
const DELTA: i32 = Dir::DELTA;
}
pub fn run() {
let idx = Indexer::<Forward> { pd: PhantomData {} };
}
PhantomData
似乎是必需的,因为我没有将Direction
存储在字段中,而它又需要大量样板文件。有没有更简单的方法来移植这个 C++ 代码?我希望避免宏或 crate 依赖。
最佳答案
我想出了一些在我的项目中使用的东西(直到 rust 支持 const 泛型):
use std::fmt;
pub trait TStaticValue<
V: Copy/*prevent interior mutation (suggested by clippy)*/
> : Sync + 'static + Clone + fmt::Debug { // these bounds turned out to be convenient for me
const VALUE : V;
}
macro_rules! define_static_value {(pub $struct: ident, $type: ty, $value: expr) => {
#[derive(Clone, Debug)]
pub struct $struct {}
impl TStaticValue<$type> for $struct {
const VALUE : $type = $value;
}
}}
然后,define_static_value
将允许您定义以下内容:
define_static_value!(pub ForwardDelta, i32, 1);
define_static_value!(pub BackwardDelta, i32, -1);
pub struct Indexer<Dir: TStaticValue<i32>> {
pd: std::marker::PhantomData<Dir>
}
impl<Dir: TStaticValue<i32>> Indexer<Dir> {
const DELTA:i32 = Dir::VALUE;
}
我知道您想避免宏,但这个解决方案对我来说相对可维护,因为所有“静态值”(即常量泛型参数)都以相同的方式模拟,并且它允许您定义和使用它们特别的和不同的类型,都通过相同的架构:每当你真正想要一个 const 泛型参数 Param
类型 CG
,您指定 Param: TStaticValue<CG>
相反。
您可能需要调整define_static_value
允许非 pub
值(value)观也是如此。
关于 PhandomData
的评论:到目前为止,我还没有找到一种方法可以避免这些问题,但是您可以确保每个结构最多一个PhantomData
成员通过将所有其他未使用的参数打包到相应的字段中(然后类型为 PhantomData<(FirstUnused, SecondUnused, ThirdUnused)>
。
关于generics - 除了使用具有关联常量的特征之外,是否有更简单的方法来为通用结构配备常量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60102224/