2015-05-31 2 views
4

Я пытаюсь напечатать Option<Box<MyStruct>>, но я получаю ошибку компиляции при попытке реализовать Display for Option<Box<MyStruct>>.Как распечатать! Опция <Box<struct>>?

use std::fmt; 

fn main() { 
    let maybe_my_struct: Option<Box<MyStruct>> = Some(Box::new(MyStruct{foo:42})); 
    println!("{}", maybe_my_struct); 
} 

struct MyStruct { 
    foo: i32, 
} 

impl fmt::Display for Option<Box<MyStruct>> { 
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 
     match self { 
      Some(MyStruct) => write!(formatter, "{}", self.foo), 
      None => write!(formatter, "No struct"), 
     } 
    } 
} 

Ошибки я получаю:

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] 

Я попытался альясинга в Option типа, а вместо реализации Display for MyOption<Box<MyStruct>>, но это дает тот же результат. Что я делаю не так?

ответ

5

Как вы можете видеть, вы не можете реализовать черту, которую вы не пишете, для типа, который вы не пишете. Это часть того, что известно как «согласованность» и существует для предотвращения действительно странных вещей, таких как привязка к библиотеке, что приводит к тому, что несвязанные части вашей программы меняют поведение.

Aliasing Option в MyOption не работает либо потому что, как вы говорите, что это псевдоним . То есть, это просто другое имя для одного и того же, это не настоящий, другой тип.

Теперь, если вы пишете обертка вокруг Option так:

struct MyOption<T>(Option<T>); 

тогдаMyOption будет новый, особый тип, который вы можете реализовать признак для. Конечно, вы захотите написать методы для обертывания и разворачивания фактического Option, который вы храните.

... но это все не имеет значения, так как вы также могут просто получить Debug для своей структуры и использовать это.

fn main() { 
    let maybe_my_struct: Option<Box<MyStruct>> = Some(Box::new(MyStruct{foo:42})); 
    println!("{:?}", Some(maybe_my_struct)); 
} 

#[derive(Debug)] 
struct MyStruct { 
    foo: i32, 
} 

Или, если вы действительно хотите, чтобы пользовательские отображения логики для Option<Box<MyStruct>> комбинации, вы можете использовать значение маркеров (этот же подход используется Path в стандартной библиотеке, кстати). Например:

use std::fmt; 

fn main() { 
    let maybe_my_struct: Option<Box<MyStruct>> = Some(Box::new(MyStruct{foo:42})); 
    println!("{:?}", maybe_my_struct); 

    // Instead of displaying directly, display via a custom marker. 
    println!("{}", maybe_my_struct.display()); 
    println!("{}", None::<Box<MyStruct>>.display()); 
} 

#[derive(Debug)] 
struct MyStruct { 
    foo: i32, 
} 

// This is the marker we'll use to define our custom Display impl. 
struct MmsDisplay<'a>(&'a Option<Box<MyStruct>>); 

// This trait lets us extend Option<Box<MyStruct>> with a new method. 
trait CustomMmsDisplay { 
    fn display<'a>(&'a self) -> MmsDisplay<'a>; 
} 

impl CustomMmsDisplay for Option<Box<MyStruct>> { 
    fn display<'a>(&'a self) -> MmsDisplay<'a> { 
     MmsDisplay(self) 
    } 
} 

// And here's the display logic. 
impl<'a> fmt::Display for MmsDisplay<'a> { 
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 
     match *self.0 { 
      Some(ref ms) => write!(formatter, "{}", ms.foo), 
      None => write!(formatter, "No struct"), 
     } 
    } 
} 
Смежные вопросы