Возврат типов с трейтами
Часть раздела Объектно-ориентированное программирование путешествия по Rust на Coddy. Урок 43 из 61.
Вы использовали ограничения трейтов, чтобы ограничить типы, которые может принимать function. Но как насчёт того, что function возвращает? Синтаксис impl Trait позволяет указать, что function возвращает «некоторый тип, реализующий этот трейт», не называя конкретный тип.
Вот синтаксис в действии:
trait Summary {
fn summarize(&self) -> String;
}
struct Article {
headline: String,
}
impl Summary for Article {
fn summarize(&self) -> String {
self.headline.clone()
}
}
fn create_summary() -> impl Summary {
Article { headline: String::from("Breaking News!") }
}
Тип возвращаемого значения impl Summary сообщает вызывающим: «вы получите что-то, что implements Summary». Вызывающий может использовать любой method из трейта, но need знать, что фактический тип — это Article.
Это особенно полезно, когда тип concrete сложный или когда вы хотите скрыть детали реализации. function обещает возможность (трейт), а не конкретный тип.
Однако есть важное ограничение: function должна вернуть ровно один concrete тип. Нельзя условно возвращать разные типы, которые implements один и тот же трейт. Для этого требуются объекты трейтов, о которых ты узнаешь позже.
// Это работает — всегда возвращает Article
fn make_item() -> impl Summary {
Article { headline: String::from("Hello") }
}
// Это бы НЕ скомпилировалось — два разных типа
// fn make_item(flag: bool) -> impl Summary {
// if flag { Article { ... } } else { Tweet { ... } }
// }
Задание
ЛегкоДавайте создадим фабрику поздравительных открыток, которая использует возвращаемый тип impl Trait, чтобы скрыть детали реализации! Вы создадите function, которая возвращает «что-то, способное приветствовать», не раскрывая конкретный тип вызывающему коду.
Вы организуете код в двух файлах:
greetings.rs: Определите публичный трейтGreetсgreetmethod, который принимает&selfи возвращаетString. Затем создайте структуруCard(она не обязана быть публичной!) с полемmessage(String). Реализуйте трейтGreetдляCard, возвращая сообщение. Наконец, создайте публичнуюfunctionс именемcreate_greeting, которая принимает параметр типаStringи возвращаетimpl Greet. Этаfunctionдолжна создать и вернутьCardс переданным сообщением.main.rs: Подключите модуль greetings и используйте предоставленные входные данные, чтобы вызватьcreate_greeting. В этом и заключается преимущество: ваш главный файл вообще ничего не знает о типеCard. Он знает только, что получил нечто, что реализуетGreet. Вызовитеgreetmethodу возвращённого значения и выведитеresult.
Главная идея заключается в том, что Card остаётся приватным для модуля, но вызывающий код всё ещё может использовать его через интерфейс трейта. function обещает возможность (приветствие), а не конкретный тип.
Ваш вывод должен отображать приветствие:
{message}Например, при вводе Happy Birthday!:
Happy Birthday!А при вводе Congratulations on your promotion!:
Congratulations on your promotion!Вы получите одни входные данные: сообщение-приветствие.
Попробуйте сами
mod greetings;
use greetings::Greet;
fn main() {
// Прочитать приветственное сообщение из ввода
let mut input = String::new();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let message = input.trim().to_string();
// TODO: Вызовите create_greeting с сообщением
// Note: Вы не знаете конкретный тип — только то, что он реализует Greet!
// TODO: Вызовите метод greet и выведите результат
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Методы и поведение
Введение в блоки реализацииПараметр SelfИзменяемые методыАссоциированные функцииНесколько блоков реализацииЦепочки вызовов методовИтоги: действия с Rectangle4Проект: Виртуальный питомец
Определение питомцаКормление питомца2Инкапсуляция и модули
Основы модулейКлючевое слово PublicПриватные поляГеттерыСеттерыИтоги — Безопасный сейф5Обобщения
Обобщённые структурыОбобщённые методыНесколько обобщённых типовОбобщённые функцииПовторение — Координатная точка8Трейты как ограничения
Синтаксис ограничений трейтовМножественные ограниченияКонструкция whereВозврат типов с трейтамиИтоги — Обобщённый принтер11Паттерны проектирования в Rust
Паттерн NewtypeКомпозицияТрейт DropFrom и IntoИтоги — Мок-объект Smart Pointer3Продвинутые перечисления
Перечисления с даннымиМетоды в перечисленияхСопоставление вариантов с даннымиСнова об Option EnumИтоги — перечисление Shape6Определение трейтов
Что такое трейт?Реализация трейтовРеализации по умолчаниюПереопределение реализаций по умолчаниюТрейты с параметрамиИтоги — Media PlayerПотренируйтесь самостоятельно: Онлайн-компилятор Rust