1

I'm implementing a trait for &[u8] but I cannot use self in the trait implementation. I assume that the trait can not detect the type and I should use a where clause, but I don't know how can I use it without an implementor.

use std::fmt::Debug;

pub trait Xor: Debug {
    fn xor(&self, key_bytes: &[u8]) -> &[u8] {
        for n in &self[..] {
            dbg!(n);
        }
        unimplemented!()
    }
}

impl Xor for [u8] {}

fn main() {
    let xa = b"1234";
    xa.xor(b"123");
}

Playground

error[E0608]: cannot index into a value of type `&Self`
 --> src/main.rs:5:19
  |
5 |         for n in &self[..] {
  |                   ^^^^^^^^
trent
  • 25,033
  • 7
  • 51
  • 90
  • 1
    That said, I suspect this is an XY problem in that you're trying to write a [provided method of the trait](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=6e6626073599ceab8c80a0145c1f40d5) when really you just want to implement it [for `[u8]` alone](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=173a4b274942e7684184f5d306ab6dda). – trent Nov 05 '19 at 11:44
  • @trentcl: is it possible to implement the trait for several kind of types without implementor ? check the following playground : https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=3f7ba1000bb371d5380fd249cebd2283 – Johnny Marcove Nov 05 '19 at 11:49
  • 1
    Sure, if they have some commonality, like implementing a common trait. `String` and `&[u8]` both implement `AsRef<[u8]>`, so you can use that to get an indexable byte slice: [playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=bfd417e8659dd6bb46160c210d3ad448) – trent Nov 05 '19 at 11:54

1 Answers1

5

There are two places you can write the body of a trait method:

  • inside the trait itself, as a provided method
  • inside an impl block.

If a method is not provided, it is required, which means all implementors have to write their own body in the appropriate impl block.

Provided methods can only use properties that are common to all the implementors of the trait, which means you can only use other trait methods or methods of supertraits (like : Debug). But methods in an impl block may use properties that are specific to the type implementing the trait. You want to use something specific to [u8] -- indexing via [..] -- so xor should be a required method:

pub trait Xor {
    fn xor(&self, key_bytes: &[u8]) -> &[u8];
}

impl Xor for [u8] {
    fn xor(&self, key_bytes: &[u8]) -> &[u8] {
        for n in &self[..] {
            dbg!(n);
        }
        unimplemented!()
    }
}

Provided methods are usually for conveniences that only use other methods of the same trait, like most of the methods on Iterator (see Why don't we implement all the functions from Iterator to implement an iterator?).

is it possible to implement the trait for several kind of types [without writing multiple impl blocks]?

Yes, if there is a trait that exposes the functionality you would use to write Xor, you may use that trait to write a generic impl. For example, String and [u8] both implement AsRef<[u8]>, so you can use that to write an impl that applies to both:

impl<T: ?Sized + AsRef<[u8]>> Xor for T {
    fn xor(&self, key_bytes: &[u8]) -> &[u8] {
        for n in &self.as_ref()[..] {
            dbg!(n);
        }
        unimplemented!()
    }
}

Playground link.

See also

trent
  • 25,033
  • 7
  • 51
  • 90