How do I bound a trait with a supertrait that uses

2020-02-13 13:17发布

I have a trait Trait with an associated type Trait::Associated. I am trying to bound the trait by requiring that it be indexable by its associated type, as shown here:

use std::ops::Index;

pub trait Trait: Index<Trait::Associated> {
    type Associated;
}

However, the compiler complains that the associated type is ambiguous

error[E0223]: ambiguous associated type
 --> src/main.rs:3:24
  |
3 | pub trait Trait: Index<Trait::Associated> {
  |                        ^^^^^^^^^^^^^^^^^ ambiguous associated type
  |
  = note: specify the type using the syntax `<Type as Trait>::Associated`

I also tried referring to the associated type as Self::Associated, but then the compiler protests about a cyclic reference between the type and the trait:

error[E0391]: cyclic dependency detected
 --> src/main.rs:3:1
  |
3 | pub trait Trait: Index<Self::Associated> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic reference
  |
note: the cycle begins when computing the supertraits of `Trait`...
 --> src/main.rs:3:1
  |
3 | pub trait Trait: Index<Self::Associated> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  = note: ...which then again requires computing the supertraits of `Trait`, completing the cycle.

Finally, I also tried explicitly implementing Index for Trait:

pub trait Trait {
    type Associated;
}

impl<T: Trait> Index<T::Associated> for T {
    type Output = str;

    fn index(&self, associated: T::Associated) -> &'static str {
        "sup"
    }
}

Unfortunately that fails too:

error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g. `MyStruct<T>`)
 --> src/main.rs:7:1
  |
7 | impl<T: Trait> Index<T::Associated> for T {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
  |
  = note: only traits defined in the current crate can be implemented for a type parameter

Am I trying to do something unreasonable here? Is there a way of achieving something similar, without having to use generics?

Playground.

标签: rust
2条回答
走好不送
2楼-- · 2020-02-13 13:32

I think the following provides the semantics you want, taking the approach of your second attempt.

pub trait Trait {
    type Associated;
}

impl<T> Index<T> for Trait<Associated = T> {
    type Output = str;

    fn index(&self, associated: T) -> &'static str {
        "sup"
    }
}
查看更多
Summer. ? 凉城
3楼-- · 2020-02-13 13:51

You are close, very close.

The Trait does not assume that any reference to Trait in its definition refers to the current type. After all, you could wish to refer to other types also implementing Trait.

In order to specify that you want a specific type, you should heed the compilers note: use <Type as Trait>::Associated, where Type is the current type.

When defining the Trait, how do you refer to the concrete type for which it will be instantiated? You use Self!

The solution is:

pub trait Trait: Index<<Self as Trait>::Associated> {
    type Associated;
}
查看更多
登录 后发表回答