Rust 1.75 中的函数与递归:详细指南
Функции и рекурсия в Rust
Представь, что ты пишешь инструкцию для робота. Если каждый раз, когда нужно сложить два числа, писать заново всю цепочку действий — это будет долго и запутанно. Функции — это как готовые блоки инструкций, которые можно вызывать по имени. Они помогают не повторять один и тот же код, делают программу понятной и аккуратной.
Рекурсия — это когда функция вызывает саму себя. Как матрёшка: внутри большой матрёшки — такая же, но поменьше. Рекурсия помогает решать задачи, которые можно разбить на такие же, но более простые подзадачи.
Основной синтаксис функций
Функция в Rust начинается с ключевого слова fn. После имени в круглых скобках идут параметры (входные данные). После стрелки -> указывается тип возвращаемого значения. Тело функции — в фигурных скобках {}.
fn имя_функции(параметр1: тип, параметр2: тип) -> тип_результата {
// действия
результат // последнее выражение без точки с запятой — это возврат
}
Простой пример — функция для сложения двух чисел (как в задаче про семейный бюджет):
use std::io;
fn summa(a: i32, b: i32) -> i32 {
a + b // возвращаем сумму
}
fn main() {
let mut input = String::new();
println!("Введи два числа через пробел:");
io::stdin().read_line(&mut input).expect("Ошибка чтения");
let parts: Vec<&str> = input.trim().split_whitespace().collect();
let x: i32 = parts[0].parse().unwrap();
let y: i32 = parts[1].parse().unwrap();
let result = summa(x, y);
println!("Сумма доходов: {}", result);
}
Сравнение и выбор (задача про температуры)
Функция может принимать два значения и возвращать одно из них. Например, найдём бóльшую температуру:
use std::io;
fn max_temperature(t1: f64, t2: f64) -> f64 {
if t1 > t2 {
t1
} else {
t2
}
}
fn main() {
let mut input = String::new();
println!("Введи две температуры через пробел (например, 23.5 18.2):");
io::stdin().read_line(&mut input).expect("Ошибка");
let parts: Vec<&str> = input.trim().split_whitespace().collect();
let temp1: f64 = parts[0].parse().unwrap();
let temp2: f64 = parts[1].parse().unwrap();
let higher = max_temperature(temp1, temp2);
println!("Более высокая температура: {}", higher);
}
Проверка чётности
Функция может возвращать не только числа, но и логическое значение bool (true/false). Проверим, чётное ли число коробок:
use std::io;
fn is_even(n: i32) -> bool {
n % 2 == 0 // если остаток от деления на 2 равен 0 — число чётное
}
fn main() {
let mut input = String::new();
println!("Сколько коробок произведено?");
io::stdin().read_line(&mut input).expect("Ошибка");
let boxes: i32 = input.trim().parse().unwrap();
if is_even(boxes) {
println!("Число коробок чётное, можно упаковывать в пары.");
} else {
println!("Число коробок нечётное, одна коробка останется без пары.");
}
}
Рекурсия: реверс строки
Рекурсивная функция — это функция, которая вызывает саму себя. Разберём задачу: вывести строку задом наперёд. Идея: берём первый символ, а для оставшейся части строки снова вызываем ту же функцию.
use std::io;
fn reverse_string(s: &str) -> String {
if s.len() <= 1 {
// если в строке 0 или 1 символ — возвращаем как есть
s.to_string()
} else {
// берём последний символ + рекурсивно обрабатываем остаток
let last = &s[s.len()-1..];
let rest = &s[..s.len()-1];
format!("{}{}", last, reverse_string(rest))
}
}
fn main() {
let mut input = String::new();
println!("Введи строку для реверса:");
io::stdin().read_line(&mut input).expect("Ошибка");
let text = input.trim();
let reversed = reverse_string(text);
println!("Перевёрнутая строка: {}", reversed);
}
Рекурсия: поиск минимума в списке
Найдём самую низкую температуру за день. Список будем передавать в функцию как срез (&[i32]). Рекурсия: если в списке один элемент — он и есть минимум. Иначе сравниваем первый элемент с минимумом из остатка списка.
use std::io;
fn find_min(arr: &[i32]) -> i32 {
if arr.len() == 1 {
arr[0]
} else {
let min_of_rest = find_min(&arr[1..]);
if arr[0] < min_of_rest {
arr[0]
} else {
min_of_rest
}
}
}
fn main() {
println!("Введи температуры через пробел (например: 15 12 18 10 14):");
let mut input = String::new();
io::stdin().read_line(&mut input).expect("Ошибка");
let numbers: Vec<i32> = input
.trim()
.split_whitespace()
.map(|s| s.parse().unwrap())
.collect();
let min_temp = find_min(&numbers);
println!("Самая низкая температура за день: {}", min_temp);
}
Частые ошибки новичков
- Забыть
returnили точку с запятой: В Rust последнее выражение в функции автоматически возвращается, но если поставить точку с запятой — оно станет инструкцией и ничего не вернёт. Будет ошибка компиляции. - Бесконечная рекурсия: Если не написать условие остановки (базовый случай), функция будет вызывать себя бесконечно, пока не закончится память. Всегда проверяй, когда рекурсия должна остановиться.
- Путаница с типами: В Rust строгая типизация. Нельзя просто так сложить
f64иi32— нужно явно преобразовывать типы. - Забыть про
&для строк: В Rust строка — сложный тип. Функции часто принимают&str(ссылку на строку), а не саму строкуString.
Итоговый пример: "Калькулятор скидки в магазине"
Представь, что в магазине действует акция: если сумма покупки больше 1000 рублей, дают скидку 10%. Напишем функцию, которая считает итоговую цену, а затем рекурсивную функцию, которая применяет скидку несколько раз (например, если товар участвует в двух акциях).
use std::io;
// Обычная функция: применяет скидку один раз
fn apply_discount(price: f64) -> f64 {
if price > 1000.0 {
price * 0.9 // скидка 10%
} else {
price
}
}
// Рекурсивная функция: применяет скидку n раз
fn apply_discount_n_times(price: f64, times: i32) -> f64 {
if times == 0 {
price // базовый случай: скидок больше нет
} else {
let discounted = apply_discount(price);
apply_discount_n_times(discounted, times - 1)
}
}
fn main() {
let mut input = String::new();
println!("Введи сумму покупки:");
io::stdin().read_line(&mut input).expect("Ошибка");
let amount: f64 = input.trim().parse().unwrap();
println!("Введи количество применений скидки:");
input.clear();
io::stdin().read_line(&mut input).expect("Ошибка");
let n: i32 = input.trim().parse().unwrap();
let final_price = apply_discount_n_times(amount, n);
println!("Итоговая цена после {} применений скидки: {:.2}", n, final_price);
}
Теперь ты знаешь, как с помощью функций и рекурсии решать самые разные задачи — от подсчёта бюджета до обработки списков. Главное — разбивай задачу на маленькие шаги и не бойся, что функция вызывает саму себя. Это как лестница: чтобы спуститься с верхнего этажа, нужно сначала сделать шаг на предыдущий!