[−][src]Struct terminator::Terminator
A type that lets you output your error as Display
for fn main() -> Result<(), Error>
Trait Implementations
impl<T: Into<Box<dyn Error>>> From<T> for Terminator
[src]
This impl block is what does all of the work. Rust has some rules regarding what traits can be implemented for what. Initially the this was what was written:
use std::error::Error; impl<T: Error> From<T> for Terminator {
However, we run into issues of cohesion and specialization. There exists an impl defined in stdlib of this form:
impl<T> From<T> for T {
Which impl then should Rust use? While we know it's more specialized rustc
does not. On top
of this we are violating coherence meaning that we have more than one impl for each given type.
What's a programmer to do then in this case? We want to be able to say I want to restrict this
to types that implement std::error::Error
. Well the good news is that we can with Into
and
some Box
magic.
This is the actual impl that does all our magic:
use std::error::Error; impl<T: Into<Box<dyn Error>>> From<T> for Terminator {
We are not asking for any given T
that impls std::error::Error
! We are asking only the ones
that can turn into a Box<dyn Error>
. Since we are then turning into another type we're not
actually breaking cohesion. Dynamic dispatch allows us to do what we originally wanted with
only some overhead. With this impl ?
now works for any type that can turn into Box<dyn Error>
which should be all error types that implement std::error::Error
.
Why do we care so much about std::error::Error
? The neat thing is that besides restricting
ourselves to only types that are errors, we also get a type that implements Display
since
that is one of std::error::Error
's trait bounds. What is a little less known is that if you
implement Display
for a type, you implicitly get ToString
. It's kind of like how if you
implement From
you automatically get Into
. As a result calling to_string()
on this error
type gives us what it would look like if it was display, so during our conversion we just call
.into().to_string()
on the input to From
and store the value to then be dumped to stdout.
Then all we have after this is a simple Debug
implementation for Terminator
that just dumps
that string out as if it was Display
!
impl Debug for Terminator
[src]
A manually implemented implementation of Debug
that writes the error out to stderr as if it
was Display
Auto Trait Implementations
impl Send for Terminator
impl Unpin for Terminator
impl Sync for Terminator
impl UnwindSafe for Terminator
impl RefUnwindSafe for Terminator
Blanket Implementations
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<T> From<T> for T
[src]
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
fn borrow_mut(&mut self) -> &mut T
[src]
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,