How to add constaint that one generic type implements another generic type


#1
use std::ops::DerefMut;

trait Action {
    type Target: ?Sized;

    fn run(self, target: &mut Self::Target);
}

struct SayPersonName;

impl Action for SayPersonName {
    type Target = Person;

    fn run(self, target: &mut Self::Target) {
        println!("{}", target.name());
    }
}

trait Person {
    fn name(&self) -> &String;
}

struct Hero {
    name: String,
}

impl Hero {
    fn run<A, T>(&mut self, action: A)
        where A: Action<Target = T>,
              Hero: DerefMut<Target = T>
    { // Here It fails to compile
        action.run(self);
    }
}

impl Person for Hero {
    fn name(&self) -> &String {
        &self.name
    }
}

fn main() {
    let mut hero = Hero { name: String::from("My hero") };
    let action = SayPersonName;
    hero.run(action);
}

#2

Is this what you’re trying to do?

trait Action {
    type Target: ?Sized;

    fn run(self, target: &mut Self::Target);
}

struct SayPersonName;

impl Action for SayPersonName {
    type Target = Person;

    fn run(self, target: &mut Self::Target) {
        println!("{}", target.name());
    }
}

trait Person {
    fn name(&self) -> &String;
}

struct Hero {
    name: String,
}

impl Hero {
    fn run<A>(&mut self, action: A) where A: Action<Target=Person> {
        action.run(self);
    }
}

impl Person for Hero {
    fn name(&self) -> &String {
        &self.name
    }
}

fn main() {
    let mut hero = Hero { name: String::from("My hero") };
    let action = SayPersonName;
    hero.run(action);
}

#3

No. I want to pass two different actions those accept different traits those are implemented by Hero.


#4

Oh, right, sorry… I think you want something like this:

#![feature(unsize)]
use std::marker::Unsize;

trait Action {
    type Target: ?Sized;

    fn run(self, target: &mut Self::Target);
}

struct SayPersonName;

impl Action for SayPersonName {
    type Target = Person;

    fn run(self, target: &mut Self::Target) {
        println!("{}", target.name());
    }
}

trait Person {
    fn name(&self) -> &String;
}

struct Hero {
    name: String,
}

impl Hero {
    fn run<A, T:?Sized>(&mut self, action: A)
        where A: Action<Target = T>,
              Hero: Unsize<T>
    {
        action.run(self);
    }
}

impl Person for Hero {
    fn name(&self) -> &String {
        &self.name
    }
}

fn main() {
    let mut hero = Hero { name: String::from("My hero") };
    let action = SayPersonName;
    hero.run::<SayPersonName, Person>(action);
}

#5

I did not check out yet. But it seems promising. Thanks.