Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust equivalent to Swift's extension methods to a protocol?

In Swift I can attach extension methods to any of struct, enum or protocol(same with trait in Rust).

protocol Foo1 {
    func method1() -> Int 
}
extension Foo1 {
    func method2() {
        print("\(method1())")
    }
}

Then all types conforming the protocol Foo1 now all have method2(). This is very useful to build "method chaining" easily.

How to do same in Rust? This doesn't work with an error.

struct Kaz {}

impl Foo for Kaz {}

trait Foo {
    fn sample1(&self) -> isize { 111 } 
}

impl Foo {
    fn sample2(&self) {
        println!("{}", self.sample1());
    }
}

fn main() {
    let x = Kaz {};
    x.sample1();
    x.sample2();
}

Here's the error.

warning: trait objects without an explicit `dyn` are deprecated
  --> src/main.rs:13:6
   |
13 | impl Foo {
   |      ^^^ help: use `dyn`: `dyn Foo`
   |
   = note: `#[warn(bare_trait_objects)]` on by default

error[E0599]: no method named `sample2` found for type `Kaz` in the current scope
  --> src/main.rs:22:7
   |
3  | struct Kaz {}
   | ---------- method `sample2` not found for this
...
22 |     x.sample2();
   |       ^^^^^^^ method not found in `Kaz`

error: aborting due to previous error
like image 317
eonil Avatar asked Nov 14 '19 08:11

eonil


1 Answers

In Rust, you can use extension traits, that is a trait with a generic implementation for all types T that implement the base trait:

struct Kaz {}

impl Foo for Kaz {}

trait Foo {
    fn sample1(&self) -> isize { 111 } 
}

trait FooExt {
    fn sample2(&self);
}

impl<T: Foo> FooExt for T {
    fn sample2(&self) {
        println!("{}", self.sample1());
    }
}

fn main() {
    let x = Kaz {};
    x.sample1();
    x.sample2();
}

Playground

like image 60
Jmb Avatar answered Sep 23 '22 08:09

Jmb