编译器允许我编写一个毯子实现这样的函数:
trait Invoke {
type S;
type E;
fn fun(&mut self) -> Result<Self::S, Self::E>;
}
impl<F, S, E> Invoke for F
where
F: Fn() -> Result<S, E>,
{
type S = S;
type E = E;
fn fun(&mut self) -> Result<S, E> {
self()
}
}
但是当我尝试添加一个函数参数时,它开始抱怨:
trait Invoke {
type A;
type S;
type E;
fn fun(&mut self, arg: Self::A) -> Result<Self::S, Self::E>;
}
impl<F, A, S, E> Invoke for F
where
F: Fn(A) -> Result<S, E>,
{
type A = A;
type S = S;
type E = E;
fn fun(&mut self, arg: A) -> Result<S, E> {
self(arg)
}
}
error[E0207]: the type parameter `A` is not constrained by the impl trait, self type, or predicates
--> src/lib.rs:9:9
|
9 | impl<F, A, S, E> Invoke for F
| ^ unconstrained type parameter
error[E0207]: the type parameter `S` is not constrained by the impl trait, self type, or predicates
--> src/lib.rs:9:12
|
9 | impl<F, A, S, E> Invoke for F
| ^ unconstrained type parameter
error[E0207]: the type parameter `E` is not constrained by the impl trait, self type, or predicates
--> src/lib.rs:9:15
|
9 | impl<F, A, S, E> Invoke for F
| ^ unconstrained type parameter
我无法理解为什么这两种情况不同。 A
不是约束签名的一部分吗?
我意识到我可以像Fn
特征声明一样重写它,但我仍然不明白:
trait Invoke<A> {
type S;
type E;
fn fun(&mut self, arg: A) -> Result<Self::S, Self::E>;
}
impl<F, A, S, E> Invoke<A> for F
where
F: Fn(A) -> Result<S, E>,
{
type S = S;
type E = E;
fn fun(&mut self, arg: A) -> Result<S, E> {
self(arg)
}
}
答案 0 :(得分:2)
类型参数代表&#34;输入&#34;类型,而相关类型代表&#34;输出&#34;类型。
Rust允许您实现通用特征的多个实例,只要类型参数的组合是唯一的。例如,单个struct Foo
可以同时实现PartialEq<Foo>
和PartialEq<Bar>
。
相反,关联类型由特征实现分配。例如,Add
特征具有类型参数RHS
和关联类型Output
。对于Self
(实施特征的类型)和RHS
的每个组合,关联的类型Output
都是固定的。
使用关联类型的主要原因是减少特征上类型参数的数量,特别是在使用该特征可能必须定义类型参数以正确绑定该特征的情况下。但是,相关类型并不总是合适的;这就是为什么我们仍然有类型参数!
Fn(Args) -> Output
特征的Fn
语法(及其朋友FnMut
和FnOnce
)隐藏了这些特征的基础实现。这是您第一次impl
再次使用不稳定的&#34;低级别&#34;语法:
#![feature(unboxed_closures)]
impl<F, S, E> Invoke for F
where
F: Fn<(), Output = Result<S, E>>,
{
type S = S;
type E = E;
fn fun(&mut self) -> Result<S, E> {
self()
}
}
如您所见,函数的结果类型是一个名为Output
的关联类型。 Output = Result<S, E>
是谓词,因此满足编译器对impl
块上类型参数的条件之一。
现在,您的第二个impl
语法不稳定了:
#![feature(unboxed_closures)]
impl<F, A, S, E> Invoke for F
where
F: Fn<(A,), Output = Result<S, E>>,
{
type A = A;
type S = S;
type E = E;
fn fun(&mut self, arg: A) -> Result<S, E> {
self(arg)
}
}
此处A
的{{1}}类型参数中使用了Fn
。
为什么这不起作用?在理论上 1 ,单个类型可以具有Fn<Args>
的多个实现,具有不同的Args
值。在这种情况下,编译器应该选择哪种实现?您只能选择一个,因为A
未作为Invoke
的类型参数传递,因此F
只能有一个Invoke
的实现。
1 实际上,您需要使用夜间编译器来执行此操作,因为直接实施Fn
,FnMut
或FnOnce
是一项不稳定的功能。在稳定版本中,编译器将仅为函数和闭包生成每个特征的最多一个实现。此外,即使在稳定的编译器上,您也可能遇到与具有类型参数的任何其他特征相同的问题。
另见: