我试图理解类型约束是如何与关联类型交互的,我偶然发现了这个我不理解的情况.我已经阅读了泛型impl中关于无约束类型的RFC,但我看不出这如何符合不允许的内容列表.直觉上,我认为对于实现Baz<T>的任何类型,这段代码都只会指定Foo中一个明确的impl.这是我错了吗,还是编译器不能实现逻辑上的飞跃?如果没有,为什么没有?

trait Foo {
    type Bar;
    fn foo(&self) -> Self::Bar;
}

trait Baz<T> {
    fn foo(&self) -> T;
}

impl<T, TBaz> Foo for TBaz
where
  TBaz: Baz<T>
{
    type Bar = T;
    fn foo(&self) -> Self::Bar {
        Baz::<T>::foo(self)
    }
}

(Playground)

error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
  --> src/lib.rs:10:6
   |
10 | impl<T, TBaz> Foo for TBaz
   |      ^ unconstrained type parameter

For more information about this error, try `rustc --explain E0207`.

推荐答案

直觉上,你错了,因为没有一个明确的impl.假设类型SomeType同时实现Baz<i32>Baz<f32>.我们将 Select 什么样的impl?关联类型Bar-i32f32的值是多少?

从形式上(从编译器的Angular 来看),您是错误的,因为您打破了the rules:

通用参数constrain如果参数在以下其中一个选项中至少出现一次,则为实现:

  • 实现的特征(如果有)
  • 实施类型
  • 作为bounds中的associated type,该类型包含约束实现的另一个参数

类型和常量参数必须始终约束实现.如果在关联类型中使用生存期,则生存期必须约束实现.

T既不出现在实现特征(Foo)中,也不出现在实现类型(TBaz)中,也不作为关联类型出现.它是一个类型参数.

我认为您的直觉失败是因为假设TBaz将只对一种类型实现Baz,可能是通过通用实现impl<T> Baz<T> for TBaz<T>.但语言并没有强制执行这一点.有一种机制可以强制执行关联的类型.如果TBaz的关联类型,则可以.

Rust相关问答推荐

何时可以在Rust中退出异步操作?

在Rust中赋值变量有运行时开销吗?

如何在 struct 的自定义序列化程序中使用serde序列化_WITH

类型批注需要静态生存期

如何使用RefCell::JOYMOMTborrow 对 struct 不同字段的可变引用

为什么这个变量不需要是可变的?

为什么`str`类型可以是任意大小(未知大小),而`string`类型的大小应该是已知的?

失真图像图形捕获Api

RUST 中的读写器锁定模式

Rust 并行获取对 ndarray 的每个元素的可变引用

有什么办法可以追踪泛型的单态化过程吗?

为什么 `tokio::join!` 宏不需要 Rust 中的 `await` 关键字?

如何在 Rust 的 Hyper 异步闭包中从外部范围正确读取字符串值

Rust:`sort_by` 多个条件,冗长的模式匹配

无法理解 Rust 对临时值的不可变和可变引用是如何被删除的

发生移动是因为 `data` 的类型为 `Vec`,它没有实现 `Copy` 特性

意外的正则表达式模式匹配

如何将切片推入数组?

在 Rust 中退出进程

使用 rust-sqlx/tokio 时如何取消长时间运行的查询