generics - 如何在 Rust 中定义具有不同 const 参数的结构族?

标签 generics rust traits type-level-computation

我在阅读页表的结构定义时遇到了这个问题(在针对 x86_64 平台的操作系统源代码中使用)。定义如下:

pub trait TableLevel {}

pub enum Level4 {}
pub enum Level3 {}
pub enum Level2 {}
pub enum Level1 {}

impl TableLevel for Level4 {}
impl TableLevel for Level3 {}
impl TableLevel for Level2 {}
impl TableLevel for Level1 {}

pub trait HierarchicalLevel: TableLevel {
    type NextLevel: TableLevel;
}

impl HierarchicalLevel for Level4 {
    type NextLevel = Level3;
}

impl HierarchicalLevel for Level3 {
    type NextLevel = Level2;
}

impl HierarchicalLevel for Level2 {
    type NextLevel = Level1;
}

这段 Rust 代码看起来不太聪明。我想知道是否可以参数化级别编号,例如1,2,3,4。使用 C++,我可以轻松实现这一点:

#include <type_traits>
#include <iostream>

template <unsigned L>
struct Level {
    typedef Level<L-1> NextLevel;
};

template <>
struct Level<1> {};

int main() {
    // The output below will give "1".
    // It checks the type `Level<3>::NextLevel::NextLevel`
    // and the type `Level<2>::NextLevel` are indeed the same type.
    std::cout
        << std::is_same<Level<3>::NextLevel::NextLevel,
                        Level<2>::NextLevel>::value
        << std::endl;
    return 0;
}

我尝试在 Rust 中做同样的事情,但我做不到,因为 Rust 不允许我使用常量参数进行算术运算。

#![feature(min_const_generics)]

struct Level<const LEVEL: usize> {}
impl <const LEVEL: usize> TableLevel for Level<LEVEL> {}

impl <const LEVEL: usize> HierarchicalLevel for Level<LEVEL> {
    // Error message from the compiler:
    // generic parameters may not be used in const operations
    // cannot perform const operation using `LEVEL`
    // help: const parameters may only be used as standalone arguments, i.e. `LEVEL`
    type NextLevel = Level<{LEVEL - 1}>;
}

是否可以在 Rust 的当前版本(可能是每晚版本)中参数化级别号?

最佳答案

不稳定的语言功能,min_const_generics它可以让你做的事情非常有限。正如您所发现的,您不能在类型参数中使用涉及泛型常量的表达式。

但是,在稳定的 Rust 中,您可以使用 typenum crate,它的工作方式与您尝试的方式类似,但会为您执行所有类型级样板。

use std::ops::Sub;
use typenum::{Unsigned, U1, U2, U3}; // 1.12.0

struct Level<N: Unsigned>(N);

impl<N: Unsigned> Level<N> {
    fn value() -> usize {
        N::to_usize()
    }
}

trait HierarchicalLevel {
    type NextLevel;
}

impl<N> HierarchicalLevel for Level<N>
where
    N: Sub<U1> + Unsigned,
    <N as Sub<U1>>::Output: Unsigned,
{
    type NextLevel = Level<<N as Sub<U1>>::Output>;
}

fn main() {
    assert_eq!(
        <Level::<U3> as HierarchicalLevel>::NextLevel::value(),
        Level::<U2>::value()
    );
}

类型U0U1U2、...表示无符号整数0、1、2、...

关于generics - 如何在 Rust 中定义具有不同 const 参数的结构族?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64675198/

相关文章:

rust - 如何将大于u8的数字写到指针?

c++ - C++ 中的特征是什么,尤其是在 boost 中

struct - 何时使用引用或框来拥有实现结构中特征的字段?

authentication - 在 git2-rs 中,克隆时如何进行身份验证?

ios - -[当我使用 UITraitCollection 变体时,UITextView setAttributedText :] stops working,

c# - 泛型的奇怪使用

java - 仅对某些方法要求 `T extends Comparable<T>`

c# - 将函数从 C++ 转换为 C#

java - 抽象数据类型,按列表中的特定变量对对象进行排序

rust - 类型不匹配解决 <impl std::future::Future as std::future::Future>::Output == std::result::Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>