Can't see conflicting trait implementation


#1

Hi all,

I’m implementing this:

pub enum OwnBorrow<T: 'static> {
    Owned(T),
    Borrowed(&'static T),
}

impl<T> OwnBorrow<T> {
    pub fn owned(val: T) -> OwnBorrow<T> { OwnBorrow::Owned(val) }
    pub fn borrowed(val: &'static T) -> OwnBorrow<T> { OwnBorrow::Borrowed(val) }

    fn reference(&self) -> &T {
        match self {
            &OwnBorrow::Owned(ref v) => v,
            &OwnBorrow::Borrowed(v) => v,
        }
    }
}

impl<T: Clone> Into<T> for OwnBorrow<T> {
    fn into(self) -> T {
        match self {
            &OwnBorrow::Owned(v) => v,
            &OwnBorrow::Borrowed(v) => v.clone(),
        }
    }
}
//...

However the compiler (nightly, a few days old) complains:

src/ownborrow.rs:26:1: 33:2 error: conflicting implementations for trait core::convert::Into [E0119]
src/ownborrow.rs:26 impl<T: Clone> Into for OwnBorrow {
src/ownborrow.rs:27 fn into(self) -> T {
src/ownborrow.rs:28 match self {
src/ownborrow.rs:29 &OwnBorrow::Owned(v) => v,
src/ownborrow.rs:30 &OwnBorrow::Borrowed(v) => v.clone(),
src/ownborrow.rs:31 }

src/ownborrow.rs:26:1: 33:2 help: run rustc --explain E0119 to see a detailed explanation
src/ownborrow.rs:26:1: 33:2 note: conflicting implementation in crate core
src/ownborrow.rs:26 impl<T: Clone> Into for OwnBorrow {
src/ownborrow.rs:27 fn into(self) -> T {
src/ownborrow.rs:28 match self {
src/ownborrow.rs:29 &OwnBorrow::Owned(v) => v,
src/ownborrow.rs:30 &OwnBorrow::Borrowed(v) => v.clone(),
src/ownborrow.rs:31 }

error: aborting due to previous error

However, I can’t see how its already implemented, and I can’t see any clue in this message. The only possible candidate I can see is:

impl<T, U> Into<U> for T where U: From<T>

but I’m not implementing From.

Clues?

Also, this seems like a type which should already exist, but I couldn’t find it. Is that because it won’t actually work? I’m concerned about the &T lifetime, and not really sure if 'static will work.

Thanks, J


#2

It does exist, it’s called Cow, for “clone on write”


#3

Ah, cool. Yes, I should use that.

But I still don’t understand what the conflicting implementation is - it’s not with Cow, is it?


#4

I’m not sure what’s causing the conflict, to be honest.


#5

By the way, you should implement From instead of Into because From automatically implements Into for free. See here for more info.


#6

Hm, in this case that would mean:

impl<T: Clone> From<OwnBorrow<T>> for T {
...
}

which Rust rejects because I can’t implement From for some random type which isn’t from this crate.


#7

This conflicts with, for any MyType, impl From<OwnBorrow<MyType>> for MyType. This impl would be allowed because both types From<OwnBorrow<MyType>> and MyType would contain local types from any given crate (MyType). Because someone might do this, implementing Into<T> for a T which is an arbitrary generic in both the struct and the trait isn’t allowed.

I would just suggest implementing the ToOwned trait instead of the Into trait, as it has no conflicting implementations, and fits the use case (turning something which might be borrowed into something which is owned).