如何定义函数类型参数(或其关联类型)的函数局部类型别名?
How to define a function-local type alias of the function's type parameters (or their associated types)?
我有一个通用函数 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
None 我的尝试完全奏效了。 是否可以避免每次都写出完整的类型名称?
我看到的唯一方法是将类型作为另一个类型参数添加到函数中。
fn foo<F, C>(container: &C)
where
F: Float,
C: Index<u32, Output = F>,
{
let pi = F::PI;
// ...
}
这通常不会导致类型推断出现问题,因为只有一种类型 F
适用于给定的 C
(至少在本例中),但它确实某些用途更嘈杂,因为要指定类型 F
您还必须为 C
放置一个占位符,反之亦然。
Diesel 也有类似的 "problem",他们已经通过 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
才能实际 运行 此代码。
我有一个通用函数 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
None 我的尝试完全奏效了。 是否可以避免每次都写出完整的类型名称?
我看到的唯一方法是将类型作为另一个类型参数添加到函数中。
fn foo<F, C>(container: &C)
where
F: Float,
C: Index<u32, Output = F>,
{
let pi = F::PI;
// ...
}
这通常不会导致类型推断出现问题,因为只有一种类型 F
适用于给定的 C
(至少在本例中),但它确实某些用途更嘈杂,因为要指定类型 F
您还必须为 C
放置一个占位符,反之亦然。
Diesel 也有类似的 "problem",他们已经通过 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
才能实际 运行 此代码。