简体   繁体   English

在为闭包特征(Fn)创建整体实现时,为什么会得到“类型参数不受限制”的信息?

[英]Why do I get “the type parameter is not constrained” when creating a blanket implementation for a closure trait (Fn)?

The compiler allows me to write blanket implementation a function like this: 编译器允许我编写类似这样的函数:

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()
    }
}

but it starts complaining when I try to add a function parameter: 但是当我尝试添加功能参数时,它开始抱怨:

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

I cannot understand why these two cases are different. 我不明白为什么这两种情况不同。 Isn't A a part of constraint signature? 是不是A约束签名的一部分?

I realized I can rewrite it like the Fn trait declaration, but I still do not get the idea: 我意识到我可以像Fn trait声明一样重写它,但是我仍然不明白这一点:

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)
    }
}

Type parameters represent "input" types, while associated types represent "output" types. 类型参数表示“输入”类型,而关联的类型表示“输出”类型。

Rust allows you to implement multiple instances of a generic trait so long as the combination of type parameters are unique. 只要类型参数的组合是唯一的,Rust允许您实现通用特征的多个实例。 For example, a single struct Foo could implement PartialEq<Foo> and PartialEq<Bar> together. 例如,单个struct Foo可以一起实现PartialEq<Foo>PartialEq<Bar>

In contrast, associated types are assigned by the trait implementation. 相反,关联类型是由trait实现分配的。 For example, the Add trait has a type parameter, RHS , and an associated type, Output . 例如, Add trait的类型参数为RHS ,而关联的类型为Output For each combination of Self (the type on which the trait is implemented) and RHS , the associated type Output is fixed. 对于Self (实现特质的类型)和RHS每种组合,相关的Output类型都是固定的。

The main reason for using associated types is to reduce the number of type parameters on traits, especially where uses of that trait might have to define a type parameter just to properly bound that trait. 使用关联类型的主要原因是减少特征上类型参数的数量,尤其是在使用该特征可能必须定义类型参数以正确绑定该特征的情况下。 However, associated types are not always appropriate; 但是,关联的类型并不总是合适的。 that's why we still have type parameters! 这就是为什么我们仍然有类型参数!


The Fn(Args) -> Output syntax for the Fn trait (and its friends FnMut and FnOnce ) hides the underlying implementation of these traits. Fn特性(及其朋友FnMutFnOnce )的Fn(Args) -> Output语法隐藏了这些特性的基础实现。 Here's your first impl again with the unstable "low-level" syntax: 这是你第一次impl与不稳定的“低层次”的语法再次:

#![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()
    }
}

As you can see, the function's result type is an associated type, named Output . 如您所见,函数的结果类型是一个关联类型,名为Output Output = Result<S, E> is a predicate, so that satisfies one of the compiler's conditions for type parameters on impl blocks. Output = Result<S, E>是一个谓词,因此满足impl块上类型参数的编译器条件之一。

Now, here's your second impl with the unstable syntax: 现在,这里是你的第二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)
    }
}

Here, A is used in Fn 's type parameter. 此处, AFn的类型参数中使用。

Why is this not valid? 为什么这无效? In theory 1 , a single type could have multiple implementations of Fn<Args> with different values of Args . 在理论上如图1所示 ,单一类型的可以具有的多个实现Fn<Args>用的不同值Args Which implementation should the compiler select in that case? 在这种情况下,编译器应选择哪种实现? You can only choose one, because A is not passed as a type parameter to Invoke , and thus F can only have a single implementation of Invoke . 您只能选择一个,因为A没有作为类型参数传递给Invoke ,因此F只能有一个Invoke实现。

1 In practice, you need to use a nightly compiler to do this, because implementing Fn , FnMut or FnOnce directly is an unstable feature. 1实际上,您需要使用夜间编译器来执行此操作,因为直接实现FnFnMutFnOnce是不稳定的功能。 On a stable versions, the compiler will only generate up to one implementation of each of these traits for functions and closures. 在稳定版本上,编译器将仅针对函数和闭包的每个特征生成最多一个实现。 Also, you could have the same issue with any other trait that has type parameters, even on a stable compiler. 而且,即使在稳定的编译器上,具有类型参数的任何其他特征也可能遇到相同的问题。

See also: 也可以看看:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么这个一揽子特征实现的类型参数不被认为是受约束的? - Why is the type parameter of this blanket trait implementation not considered to be constrained? 为什么我不能在带有类型参数的特征上添加一个全面的实现? - Why can't I add a blanket impl on a trait with a type parameter? 如何使用毯子 Into 特征实现转换回原始类型? - How do I use the blanket Into trait implementation to convert back to the original type? 为什么我们需要为 &T 全面实施 Deref 特性? - Why do we need the blanket implementation of Deref trait for &T? 全面实施受本地定义的公共性状约束的核心性状 - Blanket implementation of core traits constrained by locally-defined public trait 使用特征毯实现来限制 Rust 中的类型特征边界? - Use trait blanket implementation to restrict type trait bounds in Rust? 通用特征的一揽子特征实现 - blanket trait implementation for generic trait 当 args 不受约束时,如何为实现 trait Fn 的类型指定泛型参数? - How to specify a generic argument for a type that implements trait Fn when the args are not constrained? 我如何解决这个问题“期望一个实现 `Fn` 特性的闭包,但这个闭包只实现了 `FnOnce`” - How do I tackle this issue "expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`" 为什么需要定义特征来定义外部类型的实现? - Why do I need to define a trait to define an implementation on an external type?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM