Trait is not applicable to slice properly?

Hi! Not sure I understand why that does not work. Is that possible to make it working?

use ::core::marker::PhantomData;

fn main()
{

  trait Trait1 {}
  impl< T : Sized > Trait1 for &[ T ] {}

  trait True
  {
    fn get( self : &'_ Self ) -> bool { true }
  }
  impl< T > True for PhantomData< &'_ [ T ] >
  where
    T : Trait1 + Sized,
  {}

  fn does< T : Sized >( _ : &[ T ] ) -> PhantomData< &'_ [ T ] >
  {
    PhantomData
  }

  let got = ( &does( &[ 1, 2, 3 ] ) ).get();
  assert_eq!( got, true );

}

Output:

error[E0599]: the method `get` exists for reference `&PhantomData<&[{integer}]>`, but its trait bounds were not satisfied
   --> src/main.rs:21:39
    |
21  |   let got = ( &does( &[ 1, 2, 3 ] ) ).get();
    |                                       ^^^ method cannot be called on `&PhantomData<&[{integer}]>` due to unsatisfied trait bounds
    |
   ::: /home/kos/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/marker.rs:680:1
    |
680 | pub struct PhantomData<T: ?Sized>;
    | ---------------------------------- doesn't satisfy `PhantomData<&[{integer}]>: True`
    |
    = note: the following trait bounds were not satisfied:
            `{integer}: Trait1`
            which is required by `PhantomData<&[{integer}]>: True`

Playground.

  • Nothing implements Trait1
  • Your implementation for True requires T: Trait1 ( + Sized)
  • Therefore nothing implements True either

It works if you implement Trait1 for some integer type, e.g.

    impl Trait1 for i32 {}
1 Like

I missed in the example line: impl< T : Sized > Trait1 for &[ T ] {}
I added it. But that does not help.
My original problem does have the line.

Could you please elaborate? Thank you.

Why that work for Vec but does not for [ T ]?

  trait Trait1 {}
  impl< T : Sized > Trait1 for Vec< T > {}

  trait True
  {
    fn get( self : &'_ Self ) -> bool { true }
  }
  impl< T > True for PhantomData< T >
  where
    T : Trait1 + Sized,
  {}

  fn does< T : Sized >( _ : &T ) -> PhantomData< T >
  {
    PhantomData
  }

  let got = ( &does( &vec![ 1, 2, 3 ] ) ).get();
  assert_eq!( got, true );

OK, let's look at it with your new line but not the one I suggested.

    trait Trait1 {}
    impl<T: Sized> Trait1 for &[T] {}

We have some marker trait, Trait1. It's implemented for any reference to a slice of any type T, so long as T: Sized. It's not implemented for anything else.

    trait True {
        fn get(self: &'_ Self) -> bool {
            true
        }
    }

    impl<T> True for PhantomData<&'_ [T]> where T: Trait1 + Sized {}

Here we have another trait, True. It's implemented for PhantomData of any reference to any slice of any type T, so long as T is Sized and T implements Trait1.

But remember, only references to slices implement Trait1. Integers do not, for example. Hence the error:

    = note: the following trait bounds were not satisfied:
            `{integer}: Trait1`
            which is required by `PhantomData<&[{integer}]>: True`

Does anything meet the trait bounds on the implementation of True?:

T: Trait1 + Sized

References to slices of sized T meet the Trait1 bound, and slices can only hold sized T (so references to any slice meet the Trait1 bound), and references are themselves sized... so any reference to a slice meets both of these bounds. Let's pick one: &[String].

So, &[String]: Sized + Trait1. That satisfies the implementation of True:

impl<T> True for PhantomData<&'_ [T]> where T: Trait1 + Sized {}
// =>
// Implement True for PhantomData<&_ [T]> where T == &[String]
// =>
// Implement True for PhantomData<&'_ [&'_ [String]]>

Let's try it:

    // let got = (&does(&[1, 2, 3])).get();
    let got = PhantomData::<&[&[String]]>.get();
    assert_eq!(got, true);

Yep, that compiles.


But, from your original got, you probably wanted it to work for &[integer]. I already showed how adding an implementation of Trait1 for i32 makes it work. With your new line, is there another way?

Yes, we can adjust the bounds in the implementation of True:

-    impl<T> True for PhantomData<&'_ [T]> where T: Trait1 + Sized {}
+    impl<'pd, T> True for PhantomData<&'pd [T]> where &'pd [T]: Trait1 {}

(I could have left T: Sized in the bounds, but it's implied by being in [T] anyway.)

This works too, because now the trait bounds on the implementation of True match up with the implementation of Trait1.

1 Like

Thank you. Interesting. Trying to understand.

In this one your implementation for True (and of your does function) is different.

// Slice version
impl<T> True for PhantomData<&'_ [ T ]> where T: Trait1 + Sized {}
fn does<T: Sized>(_: &[T]) -> PhantomData<&'_ [T]> { PhantomData }
let got = (&does(&[1, 2, 3])).get(); // does::<i32>
// Vec version
impl<T> True for PhantomData<T> where T: Trait1 + Sized {}
fn does<T: Sized>(_: &T) -> PhantomData<T> { PhantomData }
let got = (&does(&vec![1, 2, 3])).get(); // does::<Vec<i32>>

If you make the Vec version more like the slice version:

impl<T> True for PhantomData<Vec<T>> where T: Trait1 + Sized {}

Then you would need a Vec<Vec<_>> similar to how you needed a &[&[_]].

Or if you make the slice version like the Vec version:

// Exactly the same for these two
impl<T> True for PhantomData<T> where T: Trait1 + Sized {}
fn does<T: Sized>(_: &T) -> PhantomData<T> { PhantomData }
// This needed adjusting to match the changed does() signature
let got = (&does(&&[1, 2, 3][..])).get();  // does::<&[i32]>
//                ^^^^^^^^^^^^^^ this part is the &[i32]
//                      and we pass an &( &[i32] )
//                      instead of a &( Vec<i32> ) like before

That's another version that works.

In general, you need to replace the type parameters (T) with the types at each step along the way and see if they match up. When T is equal to &[U], &[T] is equal to &[&[U]]... just like how when T is equal to Vec<U>, Vec<T> is equal to Vec<Vec<U>>.

When you're comparing the Vec<X> version to the &[X] version, you need to replace Vec<X> with &[X] or vice-versa even if that means you end up with a &&[X] somewhere.

(Or you could look at implementing things for unsized slices -- [X] -- directly, but this is enough for one post.)

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.