用 const 泛型表达式满足特征绑定,可能吗?

cod*_*arm 3 generics traits rust const-generics

我正在尝试利用当前不稳定的功能,generic_const_exprs让我的库的用户知道他们生成的类型的结果尺寸。

我的用例要复杂得多,但我创建了一个带有可重现错误的最小示例。主要思想是,给定 aTensor<N>作为输入,我想输出 a Tensor<M>,其中M{N + 1}。A是一个特质,它同时为和 forTensor<N>实现。这是代码:Constant<N>Variable<M>

#![allow(incomplete_features)]
#![feature(generic_const_exprs)]

struct Variable<const N: usize>;
struct Constant<const N: usize>;

trait Tensor<const N: usize> {
    fn get_dim(&self) -> usize {
        N
    }
}
trait ConvertTo<Y> {
    fn convert(&self) -> Y;
}

impl<const N: usize> Tensor<N> for Variable<N> {}
impl<const N: usize> Tensor<N> for Constant<N> {}

impl<const N: usize, const M: usize> ConvertTo<Constant<M>> for Variable<N> {
    fn convert(&self) -> Constant<M> {
        Constant::<M>
    }
}

impl<const N: usize, const M: usize> ConvertTo<Variable<M>> for Constant<N> {
    fn convert(&self) -> Variable<M> {
        Variable::<M>
    }
}

fn convert_plus_one<const N: usize, X, Y>(x: X) -> Y
where
    X: Tensor<N> + ConvertTo<Y>,
    Y: Tensor<{ N + 1 }>,
{
    x.convert()
}

fn main() {
    let x = Constant::<3>;
    let y = convert_plus_one(x);
    // At this point the compiler should know that y is a Variable<N> with N = 4
    // and it implements Tensor<4>, because Tensor<N> is implemented for Variable<N>
    assert_eq!(y.get_dim(), 4);
}
Run Code Online (Sandbox Code Playgroud)

这是编译器错误:

   Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `Variable<{_: usize}>: Tensor<{ N + 1 }>` is not satisfied
  --> src/main.rs:41:13
   |
41 |     let y = convert_plus_one(x);
   |             ^^^^^^^^^^^^^^^^ the trait `Tensor<{ N + 1 }>` is not implemented for `Variable<{_: usize}>`
   |
   = help: the trait `Tensor<N>` is implemented for `Variable<N>`
note: required by a bound in `convert_plus_one`
  --> src/main.rs:34:8
   |
31 | fn convert_plus_one<const N: usize, X, Y>(x: X) -> Y
   |    ---------------- required by a bound in this
...
34 |     Y: Tensor<{ N + 1 }>,
   |        ^^^^^^^^^^^^^^^^^ required by this bound in `convert_plus_one`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` due to previous error
Run Code Online (Sandbox Code Playgroud)

我已经没有办法解决这个问题了。我错过了什么,还是在目前的状态下这是不可能做到的generic_const_exprs

链接到 Rust 游乐场

cod*_*arm 5

感谢rust-lang Zulip 聊天@lcnr中的建议,我设法通过使用特征关联类型使其工作。这里的技巧是能够用一个表达式来表达我的界限。\xe2\x9d\xa4\xef\xb8\x8f

\n

由此:

\n
where\n    X: Tensor<N> + ConvertTo<Y>,\n    Y: Tensor<{ N + 1 }>,\n
Run Code Online (Sandbox Code Playgroud)\n

对此:

\n
where\n    X: Tensor + ConvertTo<{<X as Tensor>::N + 1}>,\n
Run Code Online (Sandbox Code Playgroud)\n

最初的示例不起作用,因为 Rust 独立评估每个特征边界。因此,它一方面试图断言这一点Constant<3>: ConvertTo<?>,另一方面又试图断言这一点?: Tensor<4>。只有同时考虑它们才有意义。

\n

特征上的关联类型,允许必要的语法确实在单个表达式中具有所有边界,这是最终结果,可以完美编译:

\n
#![allow(incomplete_features)]\n#![feature(generic_const_exprs)]\n#![feature(associated_type_bounds)]\n\nstruct Variable<const N: usize>;\nstruct Constant<const N: usize>;\n\ntrait Tensor {\n    const N: usize;\n\n    fn get_dim(&self) -> usize {\n        Self::N\n    }\n}\ntrait ConvertTo<const N: usize> {\n    type To;\n    \n    fn convert(&self) -> Self::To;\n}\n\nimpl<const N: usize> Tensor for Variable<N> {\n    const N: usize = N;\n}\nimpl<const N: usize> Tensor for Constant<N> {\n    const N: usize = N;\n}\n\nimpl<const N: usize, const M: usize> ConvertTo<M> for Variable<N> {\n    type To = Constant<M>;\n\n    fn convert(&self) -> Self::To {\n        Constant::<M>\n    }\n}\n\nimpl<const N: usize, const M: usize> ConvertTo<M> for Constant<N> {\n    type To = Variable<M>;\n    \n    fn convert(&self) -> Self::To {\n        Variable::<M>\n    }\n}\n\nfn convert_plus_one<X>(x: X) -> <X as ConvertTo<{<X as Tensor>::N + 1}>>::To\nwhere\n    X: Tensor + ConvertTo<{<X as Tensor>::N + 1}>,\n{\n    x.convert()\n}\n\nfn main() {\n    let x = Constant::<3>;\n    let y = convert_plus_one(x);\n    assert_eq!(y.get_dim(), 4);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

现在我可以休息了。

\n