Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Providing an implementation when both trait and type are not in this crate [duplicate]

Tags:

rust

traits

I want to provide an implementation of a trait ToHex (not defined by me, from serialize) for a primitive type u8:

impl ToHex for u8 {
    fn to_hex(&self) -> String {
        self.to_str_radix(16)
    }
}

The problem is I get this compiler error:

error: cannot provide an extension implementation where both trait and type are not defined in this crate

I understand the reason of this error and its logic, this is because both the trait and the primitive type are external to my code. But how can I handle this situation and provide an ToHex implementation for u8? And more generally how do you handle this kind of issue, it seems to me that this problem must be common and it should be possible and easy to extend types like this?

like image 917
user3762625 Avatar asked Jun 21 '14 10:06

user3762625


Video Answer


2 Answers

You should use a newtype struct to do this:

pub struct U8(pub u8)

impl ToHex for U8 {
    fn to_hex(&self) -> String {
        let U8(x) = *self;
        x.to_str_radix(16)
    }
}

This does mean, however, that you should wrap u8 into U8 where you need to perform this conversion:

let x: u8 = 127u8

// println!("{}", x.to_hex());   // does not compile
println!("{}", U8(x).to_hex());

This is absolutely free in terms of performance.

like image 87
Vladimir Matveev Avatar answered Sep 20 '22 13:09

Vladimir Matveev


I realize this is almost a year old, but the answer was never accepted and I think I've found an alternate solution, that I thought would be good to document here.

In order to extend the functionality of the u8 through traits, instead of trying to extend ToHex, why not create a new trait?

trait MyToHex {
    fn to_hex(&self) -> String;
}

impl MyToHex for u8 {
    fn to_hex(&self) -> String {
        format!("{:x}", *self)
    }
}

then used like so

fn main() {
    println!("{}", (16).to_hex());
}

This has the advantage that you don't have to wrap every u8 variable with a new and superfluous data type.

The disadvantage is that you still can't use a u8 in a external function (i.e std library, or one you have no control over) that requires the ToHex trait (Vladimir Matveev's solution works in this case), but from OP it sounds like all you want to do is extend u8 only inside your code.

like image 31
tsn Avatar answered Sep 17 '22 13:09

tsn