Глава 18: Обзор стандартной библиотеки

Раздел 7: Обработка времени и процессов

Содержание: 1. std::time: Работа с временем 2. std::process: Управление процессами и внешними командами 3. std::env: Доступ к окружению и аргументам Практические советы Пример: Комбинирование модулей Упражнение Заключение

В этом разделе мы разберём модули стандартной библиотеки Rust, связанные с обработкой времени и управлением процессами: std::time, std::process и std::env. Эти инструменты позволяют измерять время, запускать внешние команды и взаимодействовать с окружающей средой программы. Лекция подойдёт как новичкам, так и опытным разработчикам, желающим углубить знания. Мы рассмотрим каждый модуль с примерами, нюансами и практическими советами.


1. std::time: Работа с временем

Модуль std::time предоставляет типы для работы с временем: Duration для интервалов, Instant для измерения прошедшего времени и SystemTime для работы с системными часами.

1.1 Duration

Duration представляет промежуток времени с наносекундной точностью.

Пример: создание и использование Duration:

use std::time::Duration;

fn main() {
    let duration = Duration::from_secs(5); // 5 секунд
    println!("Секунды: {}", duration.as_secs()); // 5
    println!("Наносекунды: {}", duration.as_nanos()); // 5_000_000_000
    
    let extra = Duration::from_millis(500); // 500 миллисекунд
    let total = duration + extra;
    println!("Всего: {:.2} сек", total.as_secs_f64()); // 5.50 сек
}
    

Комментарии:

1.2 Instant

Instant используется для измерения времени выполнения кода (монотонные часы).

Пример: замер времени:

use std::time::Instant;
use std::thread;

fn main() {
    let start = Instant::now();
    thread::sleep(Duration::from_secs(1));
    let elapsed = start.elapsed();
    println!("Прошло: {:.2} сек", elapsed.as_secs_f64()); // ~1.00 сек
}
    

Комментарии:

1.3 SystemTime

SystemTime представляет момент времени относительно системных часов (может быть неточным из-за корректировок).

Пример: работа с датой:

use std::time::{SystemTime, UNIX_EPOCH};

fn main() -> std::io::Result<()> {
    let now = SystemTime::now();
    let since_epoch = now.duration_since(UNIX_EPOCH)?;
    println!("Секунд с эпохи: {}", since_epoch.as_secs());
    
    let earlier = UNIX_EPOCH + Duration::from_secs(1_000_000_000);
    println!("Прошло с 2001-09-09? {}", 
        now.duration_since(earlier).unwrap().as_secs());
    Ok(())
}
    

Комментарии:

Предупреждение: SystemTime может быть неточным из-за изменений системных часов. Для замеров используйте Instant.


2. std::process: Управление процессами и внешними командами

Модуль std::process позволяет запускать внешние процессы, взаимодействовать с их вводом-выводом и получать код завершения.

Основные типы и функции:

Пример: запуск команды ls (или dir на Windows):

use std::process::Command;

fn main() -> std::io::Result<()> {
    let output = if cfg!(target_os = "windows") {
        Command::new("cmd").args(&["/C", "dir"]).output()?
    } else {
        Command::new("ls").arg("-l").output()?
    };
    
    println!("Статус: {}", output.status);
    println!("Вывод: {}", String::from_utf8_lossy(&output.stdout));
    if !output.stderr.is_empty() {
        println!("Ошибки: {}", String::from_utf8_lossy(&output.stderr));
    }
    Ok(())
}
    

Комментарии:


6.3 std::env: Доступ к окружению и аргументам

Модуль std::env предоставляет доступ к переменным окружения, аргументам командной строки и текущему каталогу.

Основные функции:

Пример: чтение аргументов и переменных:

use std::env;

fn main() -> std::io::Result<()> {
    // Аргументы командной строки
    let args: Vec = env::args().collect();
    println!("Аргументы: {:?}", args);
    
    // Переменная окружения
    match env::var("PATH") {
        Ok(path) => println!("PATH: {}", path),
        Err(e) => println!("Ошибка PATH: {}", e),
    }
    
    // Текущая директория
    let dir = env::current_dir()?;
    println!("Текущая директория: {:?}", dir);
    Ok(())
}
    

Комментарии:

Заметка: Используйте env::args_os вместо args, если нужны сырые строки ОС (например, для некорректного UTF-8).


Практические советы


Пример: Комбинирование модулей

Программа, измеряющая время выполнения команды:

use std::env;
use std::process::Command;
use std::time::Instant;

fn main() -> std::io::Result<()> {
    let args: Vec = env::args().collect();
    if args.len() < 2 {
        println!("Укажите команду, например: cargo run -- ls");
        return Ok(());
    }
    
    let cmd = &args[1];
    let start = Instant::now();
    
    let output = Command::new(cmd).output()?;
    let elapsed = start.elapsed();
    
    println!("Статус: {}", output.status);
    println!("Время выполнения: {:.2} сек", elapsed.as_secs_f64());
    println!("Вывод: {}", String::from_utf8_lossy(&output.stdout));
    Ok(())
}
    

Этот пример использует env для аргументов, process для запуска команды и time для замера времени.


Упражнение

Напишите программу, которая:

  1. Принимает имя команды через std::env::args.
  2. Запускает команду с помощью std::process::Command.
  3. Измеряет время выполнения с Instant.
  4. Выводит код завершения, время и первые 100 символов вывода (или меньше, если вывод короче).
  5. Обрабатывает ошибки с помощью Result.

Подсказка: Используйте take для ограничения вывода.


Заключение

Модули std::time, std::process и std::env предоставляют всё необходимое для работы с временем, процессами и окружением. Они просты в использовании, но требуют внимания к обработке ошибок и кроссплатформенности. Освоив их, вы сможете создавать утилиты, скрипты и приложения с внешними зависимостями. Далее мы рассмотрим сетевые возможности.

Выполните упражнение или двигайтесь дальше!