如何为隐性特征添加别名?



我有许多以下类型签名的函数:

fn f() -> impl Fn(u32) -> u32 { 
|x: u32| x 
}

如何为Fn(u32) -> u32起一个名字,这样我就不必重复它了?虽然我可以做type X = Fn(u32) -> u32;,但 Rust 不会让我使用它,因为它是一种类型而不是特征。我必须等待trait_alias还是可以做其他事情?

你说得对。impl X要求X成为特征,并且在特征别名落地之前不可能有适当的特征别名。发生这种情况时,您将能够执行以下操作:

#![feature(trait_alias)]
trait X = Fn(u32) -> u32;
fn f() -> impl X {
|x: u32| x
}

(游乐场(


或者,当"允许"包含类型别名中的特征"时,您将能够impl trait类型别名。不过,这略有不同。当我们使用别名时type X = impl Trait,编译器将确保X的每种用法实际上是相同的具体类型。这意味着,在您的情况下,您将无法将其与多个不同的闭包一起使用,因为每个闭包都有自己独特的类型。

#![feature(type_alias_impl_trait)]
type X = impl Fn(u32) -> u32;
fn f() -> X {
|x: u32| x
}

(游乐场(

但是,这不会编译

#![feature(type_alias_impl_trait)]
type X = impl Fn(u32) -> u32;
fn f() -> X {
|x: u32| x
}
// Even a closure with exactly the same form has a different type.
fn g() -> X {
|x: u32| x
}

错误是

error: concrete type differs from previous defining opaque type use
--> src/lib.rs:10:1
|
10 | / fn g() -> X {
11 | |     |x: u32| x
12 | | }
| |_^ expected `[closure@src/lib.rs:7:5: 7:15]`, got `[closure@src/lib.rs:11:5: 11:15]`
|
note: previous use here
--> src/lib.rs:6:1
|
6  | / fn f() -> X {
7  | |     |x: u32| x
8  | | }
| |_^

(游乐场(

这与 trait 别名相反,后者允许对返回impl TraitAlias的每个函数使用不同的具体类型。有关详细信息,请参阅引入此语法和存在类型的 RFC。


在这两个功能之一落地之前,你可以得到与特征别名类似的行为,本质上是一个黑客。这个想法是创造一个新的特征,它基本上等同于原始特征,但名称更短。

// This trait is local to this crate,
// so we can implement it on any type we want.
trait ShortName: Fn(u32) -> u32 {}
// So let's go ahead and implement `ShortName`
// on any type that implements `Fn(u32) -> u32`.
impl<T: Fn(u32) -> u32> ShortName for T {}
// We can use `ShortName` to alias `Fn(u32) -> u32`.
fn f() -> impl ShortName {
|x: u32| x
}
// Moreover, the result of that can be used in places
// that expect `Fn(u32) -> u32`.
fn g<T: Fn(u32) -> u32>(x: &T) -> u32 {
x(6_u32)
}
fn main() {
// We only know that `x` implements `ShortName`,
let x = f();
// But we can still use `x` in `g`,
// which expects an `Fn(u32) -> u32` argument
let _ = g(&x);
}

(游乐场(

最新更新