Создаем Telegram бота на Rust: пошаговый гайд для смелых

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Telegram бот на Rust: почему это стоит попробовать?

Rust — это не просто очередной язык системного программирования. Он предлагает невероятную скорость, безопасность памяти без сборщика мусора и потрясающую конкурентность. В мире, где каждый миллисекунд задержки может стоить пользователя, Telegram бот на Rust становится козырем в рукаве разработчика. Вы получаете производительность, сравнимую с C++, но с гораздо более приятным синтаксисом и строгой системой типов, которая отлавливает ошибки на этапе компиляции.

В этом гайде мы пройдем путь от установки инструментов до публикации работающего бота. Вы узнаете, как обрабатывать команды, работать с состояниями и даже развернуть бота на сервере. Если вы уже знакомы с основами Rust, но никогда не писали ботов — добро пожаловать. Если вы новичок в Rust — не пугайтесь, мы будем двигаться шаг за шагом.

Что понадобится для старта

Прежде чем погрузиться в код, убедитесь, что у вас есть:

  • Rust и Cargo — установите через rustup (официальный сайт rustup.rs). Проверьте версию: rustc --version
  • Токен Telegram бота — получите его у @BotFather в Telegram. Просто отправьте /newbot и следуйте инструкциям
  • Базовое понимание async/await — в Rust это делается через tokio или async-std

Мы будем использовать библиотеку teloxide — это, пожалуй, самый зрелый и документированный фреймворк для создания Telegram ботов на Rust. Она построена на tokio и предоставляет удобный API для всех видов взаимодействий.

Шаг 1: Создание проекта и установка зависимостей

Откройте терминал и выполните:

cargo new my_telegram_bot
cd my_telegram_bot

Теперь отредактируйте файл Cargo.toml, добавив зависимости:

[package]
name = "my_telegram_bot"
version = "0.1.0"
edition = "2021"

[dependencies]
teloxide = { version = "0.12", features = ["macros"] }
tokio = { version = "1", features = ["full"] }
log = "0.4"
env_logger = "0.10"

Объяснение: teloxide — наш главный инструмент, tokio — асинхронный рантайм, log и env_logger — для удобного логирования.

Шаг 2: Первый запуск — бот-эхо

Напишем простейшего бота, который отвечает тем же текстом, что ему отправили. Замените содержимое src/main.rs на:

use teloxide::prelude::*;

#[tokio::main]
async fn main() {
    env_logger::init();
    log::info!("Запускаем бота-эхо...");

    let bot = Bot::from_env();

    teloxide::repl(bot, |bot: Bot, msg: Message| async move {
        if let Some(text) = msg.text() {
            bot.send_message(msg.chat.id, text).await?;
        }
        Ok(())
    })
    .await;
}

Обратите внимание: Bot::from_env() ищет переменную окружения TELOXIDE_TOKEN. Создайте файл .env в корне проекта или экспортируйте токен вручную:

export TELOXIDE_TOKEN="ваш_токен_бота"

Запустите бота: cargo run. Отправьте ему любое сообщение в Telegram — он должен ответить. Поздравляю, ваш первый Telegram бот на Rust работает!

Шаг 3: Обработка команд и фильтрация сообщений

Простое эхо — это скучно. Давайте добавим команды /start и /help. Используем макросы teloxide для создания диалоговой машины (dialogue).

use teloxide::prelude::*;
use teloxide::utils::command::BotCommand;

#[derive(BotCommand)]
#[command(rename = "lowercase", description = "Доступные команды:")]
enum Command {
    #[command(description = "Начать общение")]
    Start,
    #[command(description = "Показать справку")]
    Help,
}

async fn handle_command(bot: Bot, msg: Message, cmd: Command) -> ResponseResult<()> {
    match cmd {
        Command::Start => {
            bot.send_message(msg.chat.id, "Привет! Я бот на Rust. Чем могу помочь?").await?;
        }
        Command::Help => {
            bot.send_message(msg.chat.id, Command::descriptions().to_string()).await?;
        }
    }
    Ok(())
}

#[tokio::main]
async fn main() {
    env_logger::init();
    log::info!("Запускаем бота с командами...");

    let bot = Bot::from_env();

    Command::repl(bot, handle_command).await;
}

Теперь бот реагирует только на команды, начинающиеся с /. Это базовая, но уже полезная функциональность для любого Telegram бота на Rust.

Шаг 4: Работа с состояниями (диалоги)

Настоящие боты часто требуют поддержки многошаговых диалогов. Например, бот-опросник: сначала спрашивает имя, потом возраст. В teloxide это реализуется через перечисления с состояниями.

Добавим в Cargo.toml зависимость dptree (она уже включена в teloxide, но для явности укажем):

dptree = "0.2"

Теперь напишем бота, который запоминает имя пользователя:

use teloxide::prelude::*;
use teloxide::types::Message;

#[derive(Clone, Default)]
enum State {
    #[default]
    Start,
    WaitingForName,
    Done,
}

async fn handle_message(bot: Bot, msg: Message, state: State) -> TransitionOut<State> {
    match state {
        State::Start => {
            bot.send_message(msg.chat.id, "Как тебя зовут?").await?;
            next(State::WaitingForName)
        }
        State::WaitingForName => {
            let name = msg.text().unwrap_or("безымянный");
            bot.send_message(msg.chat.id, format!("Приятно познакомиться, {}!", name)).await?;
            next(State::Done)
        }
        State::Done => {
            bot.send_message(msg.chat.id, "Мы уже познакомились. Напиши /start чтобы начать заново.").await?;
            end()
        }
    }
}

#[tokio::main]
async fn main() {
    env_logger::init();
    let bot = Bot::from_env();

    Dispatcher::builder(bot, dptree::entry().endpoint(handle_message))
        .dependencies(dptree::deps![State::default()])
        .build()
        .dispatch()
        .await;
}

Этот код использует TransitionOut для переключения между состояниями. Обратите внимание: состояние хранится в памяти, поэтому при перезапуске бота оно сбрасывается. Для продакшена нужно подключа

Блоги

Рекомендаций по книгам