Menu
Coddy logo textTech

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

Часть раздела Объектно-ориентированное программирование путешествия по Rust на Coddy. Урок 33 из 61.

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

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

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

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

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

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

trait определяет, какие параметры принимает каждый method, а реализация определяет, как используются эти параметры. Это позволяет разным типам выполнять одни и те же операции по-своему: например, LoggingCalc мог бы print каждую операцию перед возвратом result.

challenge icon

Задание

Легко

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

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

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

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

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

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

Например, для inputs Hello, 3 и 4:

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

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

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

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

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Проверьте себя

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

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Rust