Tash1moto
@Tash1moto

Как правильно описать метод на rust?

Всем привет, учу rust, не понимаю для чего нужны traits.
приложил простой кусок кода, я хочу сравнить поля 2х структур в методе stronger_than
как мне это сделать ?

pub struct Animal {
    pub name: String,
    pub age: i32,
    pub strength: i32,
}

pub struct Person {
    pub name: String,
    pub age: i32,
    pub strength: i32,
}

trait BaseTrait {
    fn init(&self);
    fn stronger_than<T>(&self, target: T) -> bool;
}

impl BaseTrait for Person {
    fn init(&self) {
        println!("Hello, im Person: {}", self.name);
    }
    fn stronger_than<T>(&self, enemy: T) -> bool {
        self.strength > enemy.strength
    }

}

impl BaseTrait for Animal {
    fn init(&self) {
        println!("Hello, im Animal: {}", self.name);
    }
    fn stronger_than<T>(&self, enemy: T) -> bool {
        self.strength > enemy.strength
    }
}


fn main() {
    let person = Person { name: String::from("John"), age: 25, strength: 12 };
    let animal = Animal { name: String::from("Elephant"), age: 5, strength: 360 };

    person.init();
    animal.init();
    
    person.stronger_than(&animal);
    animal.stronger_than(&person);
}


Вот такой код рабочий, без трейтов, но входной тип не динамический

pub struct Animal {
    pub name: String,
    pub age: i32,
    pub strength: i32,
}

pub struct Person {
    pub name: String,
    pub age: i32,
    pub strength: i32,
}

impl Person {
    fn init(&self) {
        println!("Hello, im Person: {}", self.name);
    }
    fn stronger_than(&self, enemy: &Animal) -> bool {
        let result = self.strength > enemy.strength;
        println!("{} is stronger ? : {}", self.name, result);
        result
    }
}

impl Animal {
    fn init(&self) {
        println!("Hello, im Animal: {}", self.name);
    }
    fn stronger_than(&self, enemy: &Person) -> bool {
        let result = self.strength > enemy.strength;
        println!("{} is stronger ? : {}", self.name, result);
        result
    }
}


fn main() {
    let person = Person { name: String::from("John"), age: 25, strength: 12 };
    let animal = Animal { name: String::from("Elephant"), age: 5, strength: 360 };

    person.init();
    animal.init();
    
    person.stronger_than(&animal);
    animal.stronger_than(&person);
}
  • Вопрос задан
  • 168 просмотров
Пригласить эксперта
Ответы на вопрос 2
includedlibrary
@includedlibrary
Переместив параметр типа из функции в сам трейт. Трейты нужны, что писать код, который может работать с различными сущностями. Простой пример - сортировка, её можно написать для любых сущностей, определяющих трейт Ord. Вам не важно, что это за сущности, важно лишь то, что их можно сравнивать
Ответ написан
Комментировать
vabka
@vabka
Токсичный шарпист
У тебя проблема не в трейтах, а в том что ты пытаешься обращаться к полям структуры, которая передаётся как T.
Решить эту проблему можно добавлением ещё одного трейта и ограничением женерика.
Вот так должно работать:
pub struct Animal {
    pub name: String,
    pub age: i32,
    pub strength: i32,
}

pub struct Person {
    pub name: String,
    pub age: i32,
    pub strength: i32,
}
// Выделяем новый трейт, который позволяет получить силу
trait Strength {
    fn strength(&self) -> i32;
}

trait BaseTrait {
    fn init(&self);
    
    // В старом трейте принимаем target по ссылке и ограничиваем, что принимаем только такой target, который реализует trait Strength
    fn stronger_than<T>(&self, target: &T) -> bool
    where
        T: Strength;
}

impl Strength for Person {
    fn strength(&self) -> i32 {
        self.strength
    }
}


impl Strength for Animal {
    fn strength(&self) -> i32 {
        self.strength
    }
}

impl BaseTrait for Person {
    fn init(&self) {
        println!("Hello, im Person: {}", self.name);
    }

    fn stronger_than<T>(&self, enemy: &T) -> bool
    where
        T: Strength,
    {
        self.strength > enemy.strength() // вызываем метод, вместо обращения к полю
    }
}

impl BaseTrait for Animal {
    fn init(&self) {
        println!("Hello, im Animal: {}", self.name);
    }

    fn stronger_than<T>(&self, enemy: &T) -> bool
    where
        T: Strength,
    {
        self.strength > enemy.strength()
    }
}

fn main() {
    let person = Person {
        name: String::from("John"),
        age: 25,
        strength: 12,
    };
    let animal = Animal {
        name: String::from("Elephant"),
        age: 5,
        strength: 360,
    };

    person.init();
    animal.init();
    
    if person.stronger_than(&animal) {
        println!("Person is stronger than animal");
    }
    if animal.stronger_than(&person) {
        println!("Animal is stronger than person")
    }
}

Либо можно вынести функцию stronget_that в отдельный трейт и реализовать его для каждого T, по аналогии с ответом Василий Дёмин, но тогда реализаций придётся писать целую гору.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы