0Pricing
Learn Rust Coding · Урок

Предложения where и несколько ограничений

Сохраняйте читаемость сложных сигнатур.

«Предложения where и несколько ограничений» — бесплатный урок Learn Rust Coding на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Learn Rust Coding, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Learn Rust Coding содержит 4 уроков всего.

Когда встроенные ограничения становятся громоздкими

Встроенные ограничения, такие как <T: Display + Clone, U: Debug + Default>, по мере роста становится трудно читать. Rust предлагает конструкцию where как более удобную альтернативу.

Она переносит ограничения под сигнатуру, сохраняя список параметров коротким.

Базовая конструкция where

Конструкция where располагается между возвращаемым типом и телом. В каждой строке указываются тип и его ограничения.

Эти две сигнатуры означают абсолютно одно и то же; форма с where просто читается лучше.

use std::fmt::Display;

fn show<T>(value: T)
where
    T: Display,
{
    println!("{}", value);
}

Несколько ограничений в where

Можно разместить несколько ограничений — по одному для каждого параметра типа, разделив их запятыми. В каждом из них можно объединить трейты с помощью +.

Так сложную сигнатуру легче читать, чем при размещении всех ограничений в одной строке.

use std::fmt::{Display, Debug};

fn report<T, U>(a: T, b: U)
where
    T: Display + Clone,
    U: Debug,
{
    println!("{} {:?}", a, b);
}

Полный пример

Эта программа использует конструкцию where, требующую Display. Она запускается и выводит каждый аргумент с меткой.

Обратите внимание: заголовок функции остаётся аккуратным, даже несмотря на присоединённое ограничение.

use std::fmt::Display;

fn label<T>(name: &str, value: T)
where
    T: Display,
{
    println!("{} = {}", name, value);
}

fn main() {
    label("age", 30);
    label("city", "Oslo");
}

Ограничения, которые нельзя записать встроенным синтаксисом

Некоторые ограничения можно записать только в конструкции where, например ограничения для связанных или ссылочных типов. Встроенный синтаксис не позволяет выразить where Vec<T>: Clone.

Поэтому форма where обладает строго большей выразительностью.

fn duplicate<T>(items: Vec<T>) -> (Vec<T>, Vec<T>)
where
    Vec<T>: Clone,
{
    (items.clone(), items)
}

Объединение стандартных трейтов

Распространённое практическое ограничение сочетает упорядочивание, копирование и вывод. Эта обобщённая функция max_of находит наибольший элемент в срезе.

Конструкция where объединяет все три трейта, от которых зависит алгоритм.

use std::fmt::Display;

fn max_of<T>(items: &[T]) -> &T
where
    T: PartialOrd + Display,
{
    let mut best = &items[0];
    for item in items {
        if item > best { best = item; }
    }
    best
}

Запуск max_of

Вот та же идея в запускаемой программе. Срез целых чисел удовлетворяет PartialOrd + Display, поэтому вызов компилируется и выводит максимум.

Функция так же хорошо работала бы с числами с плавающей точкой или символами.

fn max_of<T>(items: &[T]) -> &T
where
    T: PartialOrd,
{
    let mut best = &items[0];
    for item in items {
        if item > best { best = item; }
    }
    best
}

fn main() {
    let nums = [3, 7, 1, 9, 4];
    println!("{}", max_of(&nums));
}

where в блоках impl

Конструкции where также присоединяются к блокам impl. Это добавляет метод только тогда, когда сохранённый тип реализует Display.

У экземпляров, чей T не реализует Display, этого метода просто не будет.

use std::fmt::Display;

struct Holder<T> { item: T }

impl<T> Holder<T>
where
    T: Display,
{
    fn print(&self) {
        println!("{}", self.item);
    }
}

Множество ограничений одновременно

Практические обобщённые интерфейсы часто требуют несколько трейтов для каждого параметра. Эта сигнатура требует клонирования, отладки и значения по умолчанию.

Конструкция where сохраняет читаемость, несмотря на три ограничения для одного типа.

use std::fmt::Debug;

fn build<T>() -> T
where
    T: Default + Clone + Debug,
{
    let v = T::default();
    v.clone()
}

Выбор между inline и where

Используйте встроенные ограничения для одного-двух простых условий. Переходите к where, если параметров много, списки трейтов длинные или ограничения относятся к сложным типам.

Оба варианта компилируются в одинаковый код; выбор зависит только от удобства чтения.

where со временами жизни

Конструкция where может содержать связи между временами жизни наряду с ограничениями трейтов. Это помогает организовать обобщённые сигнатуры с обоими видами ограничений.

Здесь конструкция требует, чтобы T переживал время жизни 'a.

fn keep<'a, T>(value: &'a T) -> &'a T
where
    T: 'a,
{
    value
}

Быстрая проверка

Проверьте, насколько хорошо Вы понимаете конструкции where и множественные ограничения.

Итоги

Конструкция where переносит ограничения трейтов под сигнатуру, улучшая читаемость при росте числа параметров или списков трейтов. Она также позволяет выразить ограничения для сложных типов и времён жизни, которые нельзя записать встроенным синтаксисом.

Встроенные ограничения и ограничения where компилируются одинаково, поэтому выбирайте более понятный вариант.

Часто задаваемые вопросы

Урок «Предложения where и несколько ограничений» бесплатный?

Да — полный текст урока «Предложения where и несколько ограничений» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Learn Rust Coding, подпишись на CoddyKit PRO. Курс Learn Rust Coding содержит 4 уроков всего.

Чему я научусь в уроке «Предложения where и несколько ограничений»?

Сохраняйте читаемость сложных сигнатур. Ты практикуешь Learn Rust Coding с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Learn Rust Coding?

Предыдущий опыт не требуется. Learn Rust Coding на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Предложения where и несколько ограничений»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Learn Rust Coding?

Да. Каждый урок Learn Rust Coding включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Обобщённые функции
  2. Обобщённые структуры и перечисления
  3. Ограничения трейтов
  4. Предложения where и несколько ограничений
← Назад к Learn Rust Coding