Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I add extension methods to a trait with associated types lying in a different crate?

Tags:

rust

traits

I'm trying to add an extension method to a trait in a different crate. This trait has an associated type specified on it.

pub trait Test<W> {
    type Error;

    fn do_sth(&mut self) -> Result<W, Self::Error>;
}

Why is it not possible to add a method that is using the associated type Error?

impl dyn Test<u8> {
    fn use_do_sth(&mut self) -> Result<u8: Self::Error> {
        self.do_sth()
    }
}

playground

like image 263
Okarin Avatar asked Sep 29 '19 16:09

Okarin


People also ask

Can traits have properties Rust?

Nothing in Rust prevents a trait from having a method with the same name as another trait's method, nor does Rust prevent you from implementing both traits on one type. It's also possible to implement a method directly on the type with the same name as methods from traits.

What are associated types in Rust?

Associated Types in Rust are similar to Generic Types; however, Associated Types limit the types of things a user can do, which consequently facilitates code management. Among the Generic Types of traits, types that depend on the type of trait implementation can be expressed by using the Associated Type syntax.

What are generic associated types?

GATs (generic associated types) were originally proposed in RFC 1598. As said before, they allow you to define type, lifetime, or const generics on associated types. If you're familiar with languages that have "higher-kinded types", then you could call GATs type constructors on traits.

Are Rust traits interfaces?

Rust is not an object oriented language. And traits are not exactly interfaces.


2 Answers

When you need to add a method to the external type, the only option is to use extension traits. It means that you define your own trait, with whatever methods you need, and implement it for the types you need.

When you need to add a method to all types implementing some external trait, you can use the same pattern, but instead of listing the types directly, just use the trait bound:

use std::fmt::Debug;

// This is an extension trait.
// You can force all its implementors to implement also some external trait,
// so that two trait bounds essentially collapse into one.
trait HelperTrait: Debug {
    fn helper_method(&mut self);
}

// And this is the "blanket" implementation,
// covering all the types necessary.
impl<T> HelperTrait for T where T: Debug {
    fn helper_method(&mut self) {
        println!("{:?}", self);
    }
}

Playground

The same idea could be applied to any external trait, as you wish.

like image 182
Cerberus Avatar answered Sep 25 '22 04:09

Cerberus


Do you want the following?

impl<E> dyn Test<u8, Error = E> {
    fn use_do_sth(&mut self) -> Result<u8, E> {
        self.do_sth()
    }
}

I came up with this following the compiler's hint that "the value of the associated type Error must be specified".

like image 41
phimuemue Avatar answered Sep 22 '22 04:09

phimuemue