Shanraq.org Shanraq.org
Функции
IT

Rust: с нуля до своего органайзера Урок 14 из 20

Функции

Урок 14. Отделить вычисление от вывода и объяснить передачу значений.

Текст переведён с помощью ИИ.

Предварительно: уроки 1–13. Если непонятны переменные, вернитесь к уроку 9.

Зачем это нужно

Мы уже пишем fn main(). Теперь дадим имя собственному вычислению. Функция — именованный участок кода, который можно вызвать с входными значениями и получить результат. Как рецепт одной операции: его описывают один раз и используют с разными порциями. Но функция работает только с переданными и доступными ей данными, а не «понимает» весь проект.

Разделим две задачи: посчитать остаток и напечатать его. Это поможет проверять вычисления отдельно от сообщений. Условия, блоки и их значения берём из уроков 11–12.

Запуск примера

Работаем в проекте organizer, созданном в уроке 6, в папке с Cargo.toml. Сохраните свою предыдущую работу отдельно. Замените весь src/main.rs первым примером ниже, сохраните файл и выполните cargo run в терминале этой папки. Как объяснялось в уроке 6, команда собирает и запускает программу. Остальные файлы менять не нужно; зависимости не добавляем. Каждый следующий полный пример также заменяет файл целиком. В блоке результата показан только вывод программы, без сообщений Cargo. Сначала предскажите его, потом запускайте.

До примера разберём подпись функции. В fn remaining(total: u32, done: u32) -> u32 имена и типы внутри скобок — параметры, места для входных значений; запятая их разделяет. -> u32 обещает вернуть число этого типа. В вызове remaining(total, done) конкретные передаваемые значения — аргументы; они попадают в параметры по порядку. Последнее выражение без ; становится результатом, как в блоках урока 12. Функция без -> возвращает уже знакомое ().

fn remaining(total: u32, done: u32) -> u32 {
    total - done
}

fn print_remaining(count: u32) {
    println!("Осталось: {count}");
}

fn main() {
    let total: u32 = 7;
    let done: u32 = 2;
    if done <= total {
        let count = remaining(total, done);
        print_remaining(count);
    } else {
        println!("Ошибка данных");
    }
}
Осталось: 5

Разбор

fn объявляет функцию. remaining — выбранное нами имя, «остаток». В скобках записаны параметры — имена входных значений с обязательными типами. Запятая разделяет параметры. -> u32 указывает тип возвращаемого результата. В фигурных скобках — тело функции. Последняя строка total - done без ; даёт результат, как значение блока в уроке 12.

Аргументы — конкретные значения при вызове. В remaining(total, done) передаются значения переменных вызывающей функции. Первый аргумент попадает первому параметру, второй — второму: одинаковые имена не означают связь по имени. remaining(7, 2) тоже допустимый вызов. Функция remaining не видит локальные переменные main; её total и done — собственные имена параметров. При каждом вызове параметры получают значения заново.

Объявление функции не выполняет её тело. Выполнение начинается с main, достигает вызова, выполняет вызванную функцию и возвращается к следующему действию. В этом файле объявления можно поставить до или после main: порядок объявления не задаёт порядок вызовов. Повторные вызовы не сохраняют локальный счётчик сами по себе.

print_remaining(count) только печатает. Когда -> ... отсутствует, тип результата — () из урока 12. Вывод на экран — действие, а не возвращённое число. Обычный вызов функции пишется без !; println! остаётся макросом.

Договор о входных данных

Наша remaining требует done <= total. Это предусловие: правило, которое должен обеспечить вызывающий код. Здесь main проверяет его до вызова. Сама сигнатура с u32 этого правила не доказывает. Не вызывайте remaining(2, 7): не превращайте ошибочные данные в нулевой остаток, скрывая проблему. Позже научимся явно возвращать отсутствие результата или ошибку; сейчас этот договор ограничивает пример.

Ранний возврат

return завершает текущий вызов функции немедленно, не весь процесс и не только блок if. После него указывается возвращаемое значение. В этом отдельном примере fits отвечает, помещается ли задача в доступное время; нулевая длительность не допускается нашим правилом.

fn fits(minutes: u32, available: u32) -> bool {
    if minutes == 0 {
        return false;
    }
    minutes <= available
}

fn main() {
    println!("{}", fits(0, 30));
    println!("{}", fits(15, 30));
    println!("{}", fits(40, 30));
}
false
true
false

Параметр available — доступное число минут. При нуле выполняется return false;; иначе результат даёт последнее сравнение без ;.

Типичная ошибка

Функция обещает u32, но из-за ; её блок даёт (). Ошибка E0308:

fn remaining(total: u32, done: u32) -> u32 {
    total - done;
}

fn main() {
    println!("{}", remaining(7, 2));
}

Уберите точку с запятой у последнего выражения или явно напишите return total - done;. Первый вариант для завершающего выражения короче.

Опорная карта

Аргументы → параметры → тело → возвращаемое значение → вызывающий код.

Проверьте понимание

  1. Выполняется ли функция при одном её объявлении?
  2. Что возвращает функция без -> ...?
  3. Что проверяет main перед вызовом remaining?

Сверка: нет, нужен вызов; (); выполненных задач не больше общего числа. Параметр — имя во входе объявления, аргумент — переданное при вызове значение.

Задание

Обязательное. Напишите is_short(minutes: u32) -> bool: короткой считаем задачу длительностью от 1 до 15 минут включительно. Функция должна вычислять ответ, а не печатать его. В main выведите результаты трёх вызовов с 0, 15, 16: false, true, false.

Самопроверка. Где параметр, где аргумент, где возвращаемый тип? Дополнительно вызовите функцию с 1: ожидается true. Не создавайте отдельную функцию на каждый случай.

Подсказка

Объедините сравнения minutes > 0 и minutes <= 15 с помощью &&. Не ставьте ; после последнего выражения функции. В main используйте пустые {} в println! для полученного ответа.

Эталон после самостоятельной попытки

fn is_short(minutes: u32) -> bool {
    minutes > 0 && minutes <= 15
}

fn main() {
    println!("{}", is_short(0));
    println!("{}", is_short(15));
    println!("{}", is_short(16));
}
false
true
false

Источник для проверки

Предыдущий урок · Оглавление · Следующий урок

Если вы нашли ошибку или опечатку в тексте статьи, то сообщите нам об этом

Комментарии (0)

Пока нет комментариев. Будьте первым.