Menu
Coddy logo textTech

Трейты с параметрами

Часть раздела Object Oriented Programming путешествия по Rust на Coddy — урок 33 из 61.

До сих пор наши методы типажа принимали только &self в качестве параметра. Но методы типажа могут принимать дополнительные параметры точно так же, как и обычные методы — это делает их гораздо более полезными для реальных операций.

При определении типажа вы можете включить любые необходимые параметры в сигнатуры методов:

trait Calculator {
    fn add(&self, a: i32, b: i32) -> i32;
    fn multiply(&self, a: i32, b: i32) -> i32;
}

Этот типаж Calculator требует наличия двух методов, каждый из которых принимает два целых числа в дополнение к &self. Любой тип, реализующий этот типаж, должен предоставлять обе операции с этими точными сигнатурами.

Вот как структура может это реализовать:

struct BasicCalc;

impl Calculator for BasicCalc {
    fn add(&self, a: i32, b: i32) -> i32 {
        a + b
    }
    
    fn multiply(&self, a: i32, b: i32) -> i32 {
        a * b
    }
}

Теперь вы можете использовать эти методы с аргументами:

let calc = BasicCalc;
println!("{}", calc.add(5, 3));       // 8
println!("{}", calc.multiply(4, 7));  // 28

Трейт определяет, какие параметры принимает каждый метод, в то время как реализация определяет, как эти параметры используются. Это позволяет различным типам выполнять одни и те же операции по-своему — возможно, LoggingCalc мог бы выводить каждую операцию перед возвратом результата.

challenge icon

Задание

Легко

Давайте создадим набор инструментов для манипуляции строками, где различные процессоры могут преобразовывать текст по-своему! Вы создадите типаж TextProcessor с методами, принимающими параметры, а затем реализуете его для двух различных типов процессоров.

Вы организуете свой код в трех файлах:

  • processor.rs: Определите публичный типаж TextProcessor с двумя методами, принимающими параметры:
    • repeat(&self, text: &str, times: u32) -> String — повторяет заданный текст указанное количество раз
    • truncate(&self, text: &str, max_len: usize) -> String — укорачивает текст до указанной максимальной длины
  • processors.rs: Создайте две публичные структуры, реализующие ваш типаж:
    • SimpleProcessor — unit-структура, которая повторяет текст с пробелами между повторениями (например, "Hi", повторенное 3 раза, становится "Hi Hi Hi") и усекает текст, просто обрезая его по максимальной длине
    • FancyProcessor — unit-структура, которая повторяет текст с " * " между повторениями (например, "Hi", повторенное 3 раза, становится "Hi * Hi * Hi") и усекает текст, добавляя "...", если текст был сокращен (только если исходный текст был длиннее max_len)
  • main.rs: Объедините ваши модули и продемонстрируйте, как одни и те же методы типажа дают разные результаты в зависимости от того, какой процессор вы используете.

В основном файле создайте оба процессора и используйте входные данные для их тестирования. Вы получите три входных значения: текстовую строку, количество повторений и максимальную длину.

Выведите четыре строки, показывающие поведение каждого процессора:

Simple repeat: {result}
Simple truncate: {result}
Fancy repeat: {result}
Fancy truncate: {result}

Например, при входных данных Hello, 3 и 4:

Simple repeat: Hello Hello Hello
Simple truncate: Hell
Fancy repeat: Hello * Hello * Hello
Fancy truncate: Hell...

Обратите внимание, как оба процессора выполняют один и тот же контракт TextProcessor, но каждый преобразует текст своим уникальным способом. Типаж определяет, какие параметры принимают методы, в то время как каждая реализация решает, как их использовать!

Вы получите три входных значения: текст для обработки, количество повторений (распарсить как u32) и максимальную длину для усечения (распарсить как usize).

Шпаргалка

Методы типажа могут принимать дополнительные параметры, помимо &self:

trait Calculator {
    fn add(&self, a: i32, b: i32) -> i32;
    fn multiply(&self, a: i32, b: i32) -> i32;
}

Реализация типажа с параметрами:

struct BasicCalc;

impl Calculator for BasicCalc {
    fn add(&self, a: i32, b: i32) -> i32 {
        a + b
    }
    
    fn multiply(&self, a: i32, b: i32) -> i32 {
        a * b
    }
}

Использование методов типажа с аргументами:

let calc = BasicCalc;
println!("{}", calc.add(5, 3));       // 8
println!("{}", calc.multiply(4, 7));  // 28

Типаж определяет, какие параметры принимает каждый метод, в то время как реализация определяет, как эти параметры используются.

Попробуйте сами

mod processor;
mod processors;

use processor::TextProcessor;
use processors::{SimpleProcessor, FancyProcessor};

fn main() {
    // Чтение входных данных
    let mut text = String::new();
    std::io::stdin().read_line(&mut text).expect("Failed to read line");
    let text = text.trim();
    
    let mut times_input = String::new();
    std::io::stdin().read_line(&mut times_input).expect("Failed to read line");
    let times: u32 = times_input.trim().parse().expect("Failed to parse times");
    
    let mut max_len_input = String::new();
    std::io::stdin().read_line(&mut max_len_input).expect("Failed to read line");
    let max_len: usize = max_len_input.trim().parse().expect("Failed to parse max_len");
    
    // Создание процессоров
    let simple = SimpleProcessor;
    let fancy = FancyProcessor;
    
    // TODO: Используйте процессоры для преобразования текста и вывода результатов
    // Выведите четыре строки:
    // Simple repeat: {result}
    // Simple truncate: {result}
    // Fancy repeat: {result}
    // Fancy truncate: {result}
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Object Oriented Programming