generics - 除了使用具有关联常量的特征之外,是否有更简单的方法来为通用结构配备常量?

标签 generics rust constants

我有一个类型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/

相关文章:

javascript - Javascript 中的 const 关键字作用域

C 函数中的 Const 声明和实现

struct - 如何从字符串_and_创建迭代器并将其存储在结构中?

Java : How to sort values of a HashMap with generic Key and Value?

c# - 使用泛型的类型安全 : Check T to Interface<T>

generics - F# 内联函数 : instance member constraint fail

linked-list - 从单向链表中删除节点出现错误 "cannot move out of borrowed content"

iterator - 将结构的迭代器传递给接受 Rust 中引用的函数?

php - 为什么 const 在静态函数中未定义?

swift - Swift 中的空数组和泛型有什么用?