如何定义函数的类型参数(或其相关类型)的函数局部类型别名?

问题描述 投票:3回答:2

我有一个通用的功能foo一些复杂的上下的特质界限:

use std::ops::Index;

// This trait is just as an example
trait Float {
    const PI: Self;
    fn from_f32(v: f32) -> Self;
}
// impl Float for f32, f64 ...

fn foo<C>(container: &C)
where
    C: Index<u32>,
    <C as Index<u32>>::Output: Float,
{
    // ...
}

我现在需要使用类型<C as Index<u32>>::Output在函数内部一堆(如获得通过π或::PI::from_f32(3.0))。但是,这种类型的长手工打出来,使整个代码非常冗长,难以阅读。 (注:在我真正的代码,实际类型甚至更长的时间和更难看。)

为了解决这个问题,我试图创建一个函数的局部类型别名:

// Inside of `foo`:
type Floaty = <C as Index<u32>>::Output;

但是,这将导致该错误:

error[E0401]: can't use type parameters from outer function
  --> src/lib.rs:16:20
   |
10 | fn foo<C>(container: &C)
   |    --- - type variable from outer function
   |    |
   |    try adding a local type parameter in this method instead
...
16 |     type Floaty = <C as Index<u32>>::Output;
   |                    ^ use of type variable from outer function

所以,就像其他项目,type别名也不管他们是否在功能或治疗不及时。没有任何好的想法,我试着写一个可扩展的类型的宏:

// Inside of `foo`:
macro_rules! Floaty {
    () => { <C as Index<u32>>::Output };
}

Floaty!()::PI;    // errors

尽管我有部分成功与此(Floaty!()是某种类型的上下文中有效),这与最后一行的错误:

error: expected one of `.`, `;`, `?`, `}`, or an operator, found `::`
  --> src/lib.rs:20:14
   |
20 |     Floaty!()::PI;    // errors
   |              ^^ expected one of `.`, `;`, `?`, `}`, or an operator here

error[E0575]: expected method or associated constant, found associated type `Index::Output`
  --> src/lib.rs:17:17
   |
17 |         () => { <C as Index<u32>>::Output };
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
...
20 |     Floaty!()::PI;    // errors
   |     --------- in this macro invocation
   |
   = note: can't use a type alias as a constructor

我尝试都没有完全奏效。是否有可能避免每次写出完整的类型名称?

rust type-alias
2个回答
3
投票

柴油也有类似的“问题”,他们已经通过defining non-function-local type aliases解决它。我喜欢这样的解决方案,因为您可以使用别名来清理你的特质边界,以及:

type Floaty<C> = <C as Index<u32>>::Output;

fn foo<C>(container: &C)
where
    C: Index<u32>,
    Floaty<C>: Float,
{
    let p = Floaty::<C>::PI;
    // ...
}

请注意,你必须改变你的特质Float要求,它的Sized以实际运行该代码。


4
投票

我已经看到这种情况的唯一方法是添加类型为另一种类型参数的功能。

fn foo<F, C>(container: &C)
where
    F: Float,
    C: Index<u32, Output = F>,
{
    let pi = F::PI;
    // ...
}

这通常不会引起问题的类型推断,因为只会有一种类型的F(至少在本例中)对于一个给定C的作品,但它确实使某些用途喧闹,因为至F你必须指定类型还放了占位C,反之亦然。

© www.soinside.com 2019 - 2024. All rights reserved.