Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can not implement trait from another crate for generic type from another crate parameterized with local type

Tags:

rust

This test code (playpen):

use std::fmt::{Display, Formatter, Error};

struct MyLocalType;

type MyResult = Result<MyLocalType, String>;

impl Display for MyResult {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_str("some test string")
    }
}

fn main() { 
    let r: MyResult = Ok(MyLocalType); 
    println!("{}" , r); 
}

Produces this error message:

<anon>:7:1: 11:2 error: the impl does not reference any types defined in this crate; only traits defined in the current crate can be implemented for arbitrary types [E0117]
<anon>:7 impl Display for MyResult {
<anon>:8     fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
<anon>:9         f.write_str("some test string")
<anon>:10     }
<anon>:11 }

This code successfully compiled in the January version of Rust; how can I implement it now?

like image 979
pavlov-dmitry Avatar asked Apr 22 '15 06:04

pavlov-dmitry


1 Answers

There's no direct way to solve this for a pure alias like type.

The code is the same as

impl Display for Result<MyLocalType, String>

and the compiler can't ensure that there will be no conflicting implementations in other crates (aka, can't ensure that the implementation is 'coherent'). Being able to do it is definitely useful sometimes, but it was unfortunately a bug that the compiler accepted it before.

Solutions include:

  • defining a proper wrapper type for Result, e.g. struct MyResult(Result<MyLocalType, String>);,
  • defining your own enum: enum MyResult { Ok(MyType), Err(String) },
  • define a wrapper type, but only use it when printing, i.e. write println!("{}", Wrapper(r)); instead of println!("{}", r);.

Both of these make MyResult a local type, and so the impl then should be legal.

like image 63
huon Avatar answered Oct 05 '22 06:10

huon