在Rust中检查某些属性的常量泛型

9rbhqvlz  于 2022-11-12  发布在  其他
关注(0)|答案(2)|浏览(115)

在这个练习场中,我只想为保存某个属性的const泛型参数实现一个方法:https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=3e4d5f9f27912d032308a390a56f5f94
我正在使用一个大小为零的类型,并向其添加一个方法:

pub struct Resource<const N: usize> {}

impl<const N: usize> Resource<N> {
    const fn shorten<const M: usize>(self) -> Resource<M>
    where
        [(); N - M]:, // type existence only ensured if N >= M
    {
        // Runtime checks, though they should not be needed
        if M <= N {
            Resource {}
        } else {
            panic!("Resources can only be shortened")
        }
    }
}

其思想是,如果N >= M,则Resource<N>类型可以被缩短为Resource<M>
但是,当我这样使用它时:

pub fn bar<const N: usize>(
    resource: Resource<N>,
) -> Result<((), Resource<{ N - 1 }>), Box<dyn std::error::Error>>
where
    [(); N - 1]:,
{
    Ok(((), resource.shorten::<{ N - 1 }>()))
}

出现以下编译器错误:

error: unconstrained generic constant
  --> src/main.rs:43:22
   |
43 |     Ok(((), resource.shorten::<{ N - 1 }>()))
   |                      ^^^^^^^
   |
   = help: try adding a `where` bound using this expression: `where [(); N - M]:`
note: required by a bound in `Resource::<N>::shorten`
  --> src/main.rs:8:14
   |
6  |     const fn shorten<const M: usize>(self) -> Resource<M>
   |              ------- required by a bound in this
7  |     where
8  |         [(); N - M]:, // type existence only ensured if N >= M
   |              ^^^^^ required by this bound in `Resource::<N>::shorten`

我理解(并在其他在线资源中发现)编译器对where的建议可能会产生误导(因为它不是一个常用的特性)。忽略这个建议,我不确定为什么以及在哪里首先需要这个界限。
bar中,shorten调用是在Resource<N>上执行的(从参数中清除),返回Resource<{N - 1}>(从turbo-fish中清除)。
很高兴听到一些更有经验的铁 rust 虫的想法。

rkue9o1l

rkue9o1l1#

编译器不会分析表达式(一般来说这也是不可能的)。它会进行逐字替换。如果你想编译这段代码,你需要用实际使用的值替换NM

pub fn foo<const N: usize>(
    resource: Resource<N>,
) -> Result<((), Resource<{ N - 2 }>), Box<dyn std::error::Error>>
where
    [(); N - (N - 1)]:,
    [(); (N - 1) - (N - 2)]:,
{
    let (baz, resource): ((), Resource<{ N - 1 }>) = bar::<{ N }>(resource)?;
    resource.dbg();
    // new resource is N-1; returning it as N-2 should work, as it is smaller
    // 'shorten<M>'  does not exist, if there is no conversion possible

    Ok((baz, resource.shorten::<{ N - 2 }>()))
}

pub fn bar<const N: usize>(
    resource: Resource<N>,
) -> Result<((), Resource<{ N - 1 }>), Box<dyn std::error::Error>>
where
    [(); N - (N - 1)]:,
{
    Ok(((), resource.shorten::<{ N - 1 }>()))
}

Playground

vnzz0bqm

vnzz0bqm2#

我的一个同事告诉我,液体类型(如在Haskell中)将允许对类型进行这样的计算,而不是逐字替换,正如在接受的答案中所解释的那样。
Flux project(和publication)似乎解决了这个问题,但这还为时尚早。

相关问题