Открытый канал ID 72073278341637

Записки о Rust

Процесс погружения в rust

Открыть в MAX

Публикации за период

По реакциям

Поиск и вся лента — после бесплатной регистрации. Свои даты — по подписке; владелец канала видит их бесплатно. Сортировка по реакциям — по подписке. Зарегистрироваться

Загрузка…

В Rust не принято возвращать из функций "чистый" тип, обычно для этого используется перечисление enum. Если говорить о стандартных библиотеках Rust то чаще всего возвращается

pub enum Option<T> {
Some(T),
None,
}

Предполагается, что значение может отсутствовать.

Или

pub enum Result<T, E> {
Ok(T),
Err(E),
}

для возвращения конкретного результата или ошибки.

Встречаются и другие варианты, в зависимости от того, что должно быть возвращено.

Пример с Option

fn main() {
 let num = vec![1, 2, 3, -10, 143];
 // Возвращает Option<&i32> по индексу
 let res = num.get(4);.
 match res {
     Some(value) => println!("Нашли: {}", value),
     None => println!("Не нашли"),
 }
}

Пример с Result. Кто читал предыдущие посты подобные примеры уже неоднократно встречались.


use std::io;

fn main() {
   let mut input = String::new(); // строка для ввода
   println!("Введите ваше имя:");.
// ввод с клавиатуры с проверкой ошибки с дописывания строки input
   match io::stdin().read_line(&mut input) {
       Ok(n) => {
         println!("Всего {} байтов", n);
         let mut input = "Привет ".to_string() + &input.trim() + &"!".to_string();
         println!("{}", input);
       }
       Err(error) => {
         println!("Ошибка при чтении: {}", error);
       }
   }
}

Обработка с оператором match предпочтительна, но не обязательна. В дальнейшем расскажу о других возможностях.

Описанные выше особенности языка rust входит в его основы. Это следует усвоить.
Просмотры: 33
Перейти в пост Открыть в MAX Сообщить о неточности
Сегодня тема: ввод с клавиатуры. Две не большие программки.
Одна - это просто ввод с клавиатуры строки, другая ввод с клавиатуры
с последующей попыткой преобразовать строку в целое число.


use std::io;

fn main() {
let mut input = String::new(); // строка для ввода
println!("Введите ваше имя:");.
// ввод с клавиатуры с проверкой ошибки с дописывания строки input
match io::stdin().read_line(&mut input) {
Ok(n) => {
println!("Всего {} байтов", n);
let mut input = "Привет ".to_string() + &input.trim() + &"!".to_string();
println!("{}", input);
}
Err(error) => {
println!("Ошибка при чтении: {}", error);
}
}
}

И так io::stdin().read_line(&mut input) ввод строки с клавиатуры.
Тут важно отметить, метод read_line() добавляет символы в строку,
не очищая её. Поэтому нужно использовать для этой цели
пустую строку. У нас она просто создаётся для этой цели.

Второе. Этот метод возвращает тип перечисление (enum). Поэтому
мы используем match. В зависимости от результата иы выполняем то или иное
действие. Да и не забудем про библиотеку std::io, она нужна для read_line().


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

use std::io;
use std::process;

fn main() {
let mut input = String::new(); // пустая строка
match io::stdin().read_line(&mut input) {
Ok(_) => {
// преобразовать строку в число
let number: i32 = match input.trim().parse() {
Ok(num) => num,
Err(_) => {
println!("Вы ввели некорректное значение!");
process::exit(1); // завершаем программу с кодом 1
}
};
}
Err(error) => {
println!("Ошибка при чтении: {}", error);
}
}
}

Внутренний match реагирует на ситуацию когда строка не может быть преобразована
в число. В этом случае программа заканчивает своё выполнение через использование
process::exit(1) - код выхода 1. Чтобы использовать этот метод мы подключили библиотеку
std::process.

Конечно, то что я здесь представил, надо бы обернуть в функции.
Т.е. создать свою библиотечку, которую можно использовать
в разных приложениях. Но об этом поговорим в одном из следующих постов.

Не забывайте, что оглавление по моим постам можно найти здесь

https://dzen.ru/a/aq_S5YWcNkgWfHcO

Оглавление тематическое, а на канале здесь темы идут не по порядку.
Просмотры: 30
Перейти в пост Открыть в MAX Сообщить о неточности
Сегодня поговорим о параметрах командной строки. Надеюсь, читатель умеет с ней работать. Текст программы parameters00 представлен ниже. Операционная система Alt Linux.

se std::env;

fn main() {
   // Собираем все аргументы в вектор
   let args: Vec<String> = env::args().collect();
// Первый элемент — это путь к исполняемому файлу
   println!("Путь к программе: {}", args[0]);
// Остальные элементы — это переданные параметры
   if args.len() > 1 {
       println!("Переданные прараметры");
       for arg in args[1..].iter() {
           println!("Параметр {}", arg);
       }
   } else {
       println!("Параметры не переданы.");
   }
}

Для работы с параметрами командной строки я использую библиотеку std и её модуль env. args[1..] - это так называемый срез. Метод iter превращает его в итератор, по которому мы проходим с помощью цикла.

Не забывайте, что по адресу

https://dzen.ru/a/aq_S5YWcNkgWfHcO

есть тематическое оглавление моих материалов по Rust.
Просмотры: 37
Перейти в пост Открыть в MAX Сообщить о неточности
Загружаем изображение…
Продолжаем наши изыскания в области языка Rust и функций в частности. Сегодня об анонимных функциях (замыканиях), а также об обобщённых параметрах.

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

fn main() {
// простая анонимная функция, возведение в степень
 let pwr = |n:i64|{
    n * n
 };
 println!("{}", pwr(33));
// анонимная функция без скобок
// без указания типов параметров
 let sum = |a, b|a+b;
 println!("{}",sum(222, 900));
}

В программе выше определены две анонимные функции. Если выражение в функции однострочное, то можно обойтись без фигурных скобок. Результат выполнения программы

1089
1122

Анонимные функции могут захватывать переменные и их можно передавать в другие функции в качестве параметров.

// функция с обобщённым параметром (F)
fn dv<F>(divi:F, b:i64).
where.
  F:Fn(i64)->&'static str,.
{
  println!("{} {}", divi(b), divi(b+1));
}
fn main() {
// анонимная функция с замыканием (захватом переменной a)
  let a:i64 = 7;
  let div = |n:i64| {
     if n % a == 0 {
       "Делится"
     } else {
       "Не делится"
     }
  };
  println!("{} {}", div(49), div(50));
  dv(div, 56);
}


Что мы видим?
1. Анонимная функция захватывает переменную a.
2. Анонимная функция передаётся в качестве параметра.

Самое интересное, как определяется функция, у которой есть параметр -функция. Важно <F> - мы указываем обобщённый параметр. После слова where указывается какому условию он должен удовлетворять. Таким образом в функцию можно передавать и другие параметры-функции, если они удовлетворяют указанному условию (соответствуют сигнатуре).

Не забываем, что по адресу
https://dzen.ru/a/aq_S5YWcNkgWfHcO

перечислены статьи по Rust, распределённые по темам, которые опубликовал в данном канале.
Просмотры: 33
Перейти в пост Открыть в MAX Сообщить о неточности
Загружаем изображение…
Многомодульные программы.

Как и в любом другом современном языке программирования в Rust
программа может состоять из множества модулей. Если кода много,
то способ упростить программирование.

Я пока не рассказывал об устройстве каталога, где хранится проект на языке Rust.
Но если вы уже пишите программы на Rust, то знаете, что в каьалоге с проектом,
подкаталог src, где и хранится текст (тексты) программы на Rust.
В простейшем случае там хранится один файл main.rs. Но программа может быть большой,
и приходится разбивать её на несколько моделей. А если модулей слишком много,
то приходится в src делать подкаталоги, т.е. в сущности разбивать модели ещё и на
группы. Вот как может быть устроена такая система модулей я и покажу на конкретном
примере.

В начале покажу схему каталогов
src
--conf
--modules
----new

А теперь посмотрим файловое содержимое каталогов
src:
./main.rs
conf:
./mod.rs
modules:
./mod.rs
./modul1.rs
./modul2.rs
new:
./mod.rs

Теперь не много о названиях моделей.
Модуль с именем main - главный модуль проект.
Модули с именем mod это главные модули в конкретном подкаталоге.
Т.е. связь с модулями подкаталога идёт через модули с именами mod.
Ну а теперь модеражимое всех модулей.
=======================
main.rs:
=======================
mod conf;
mod modules;

fn main() {
println!("В главном модуле");
conf::main_in_conf();....
modules::main_in_modules();....
modules::modul1::in_modul1();
modules::modul2::in_modul2();
modules::new::main_in_modules_new
();
}
=======================
conf/mod.rs:
=======================
pub fn main_in_conf() {
println!("В главном модуле каталога conf
");
}
=======================
modules/mod.rs:
=======================
pub mod modul1;.
pub mod modul2;.
pub mod new;

pub fn main_in_modules() {
println!("В главном модуле каталога module
s");
}
=======================
modules/modul1.rs:
=======================
pub fn in_modul1() {
println!("В модуле modules/modul
1");
}
=======================
modules/modul2.rs:
=======================
pub fn in_modul2() {
println!("В модуле modules/modul
2");
}
=======================
modules/new/modul2.rs:
=======================
pub fn main_in_modules_new() {
println!("В главном модуле каталога modules/ne
w");
}

Результат выполнения программы
В главном модуле
В главном модуле каталога conf
В главном модуле каталога modules
В модуле modules/modul1
В модуле modules/modul2
В главном модуле каталога modules/new

Ну вот, пока всё о многомодульности. Но только пока. Вернёмся к этому вопросу позднее.
Просмотры: 107
Перейти в пост Открыть в MAX Сообщить о неточности
Загружаем изображение…
По-старому буду называть эту структуру словарём. Хотя есть ещё одно название "ассоциированный массив". Но вот в rust это называется хэшем.

А смысл в следующем. Это список пар (ключ, значение). В rust все ключи и все значения должны быть одного типа. Хотя как обычно это требование обходится с помощью enum - перечисления. Я об этом расскажу позднее. Ниже представлен пример программы формирования хэша, перебор всех пар и получения значения по ключу.

use std::collections::HashMap;

fn main() {
// задать
   let mut sl = HashMap::new();
// добавить значения
   sl.insert(String::from("Иванов И.И."), 120000);
   sl.insert(String::from("Петров П.П."), 70000);
   sl.insert(String::from("Пупкина З.В."), 80000);
   sl.insert(String::from("Васильев-Задунайский Р.Р."), 90000);
// перебор
   for (name, salary) in &sl {
       println!("{} - {}", name, salary);
   }
// доступ по ключу
   let key = "Пупкина З.В.".to_string();
   match sl.get(&key) {
      Some(&sal) => println!("{} - {}", key,  sal),
      None => println!("{} Нет такого!", key),
   }
}

Не забывайте указать библиотеку для импортирования: use std::collections::HashMap;.

Да, доступ к значению по ключу очень быстрый. Этим и ценна данная структура.
Просмотры: 119
Перейти в пост Открыть в MAX Сообщить о неточности
Загружаем изображение…
Вернёмся к строкам. Рассмотрим теперь как сравнивать строки.
В программе ниже всё понятно. Так что, что не буду отдельно её комментировать.

use std::cmp::Ordering;

fn main() {
// сравнение на равенство
let s1 = "Привет".to_string();
let s2 = "привет".to_string();
if s1 == s2 {
println!("равны");
} else {
println!("не равны");
}
// лексиграфическое сравнение
let s11 = "Привет".to_string();
let s22 = "Привет".to_string();
match s11.cmp(&s22) {
Ordering::Less => println!("s11 < s22"),
Ordering::Equal => println!("s11 == s22"),
Ordering::Greater => println!("s11 > s22"),
}
// сравнение с константой (шаблоном)
let s = "Здравствуйте".to_string();
match s.as_str() {
"Здравствуйте" => println!("Привет"),
"До свидания" => println!("Увидимся"),
_ => println!("????"),
}
}
Просмотры: 78
Перейти в пост Открыть в MAX Сообщить о неточности
Загружаем изображение…
Продолжим о файлах. Следующая программа читает файл (текстовый) и пишет данные в другой файл, который создаётся или перезаписывается.

use std::io::Read;
use std::fs::File;
use std::io::Write;

// открыть для чтения
fn of(ps:&str) -> Result<File, std::io::Error> {
File::open(ps)
}
// создать файл
fn wf(ps:&str) -> Result<File, std::io::Error> {
File::create(ps)
}

fn main() {
let s:String = "./1.txt".to_string();
let s2:String = "./2.txt".to_string();
match of(&s) { // обработка открытия
Ok(mut file) => {
println!("Файл открыт для чтения");
let mut txt = String::new();
match file.read_to_string(&mut txt) { // чтение
Ok(_) => {
match wf(&s2) { // открыть для записи (создать)
Ok(mut file2) => {
match file2.write_all(txt.as_bytes()) { //записать
Ok(_) => println!("Записано"),
Err(_) => println!("Ошибка записи"),
}
},
Err(_) => println!("Ошибка создания"),
}
}
Err(e) => eprintln!("Не удалось прочитать данные из файла: {}", e),
}
},
Err(_e) => {
println!("Ошибка");
}
}
}

В программе должно быть всё понятно, так как подобное уже использовано в предыдущих постах. Да, может смущать вот такая вложенная структура match. Но к упрощению такой записи мы вернёмся позднее, также как позднее мы подробнее обратимся к вопросам управления файлами на Rust.
Просмотры: 49
Перейти в пост Открыть в MAX Сообщить о неточности
Вся лента — после бесплатной регистрации
ВКонтакте Телеграм Одноклассники
Избранное в datool.ru

Следите за каналом в личном кабинете

Зарегистрируйтесь в datool.ru, чтобы добавить канал «Записки о Rust» в избранное и отслеживать его показатели.

Зарегистрироваться
Для владельцев каналов

Подтвердите свой канал

Войдите или зарегистрируйтесь в datool.ru, затем добавьте нашего бота в канал по инструкции в личном кабинете. После проверки владения замок исчезнет и вам станет доступно управление каналом.

Войти или зарегистрироваться

Сообщить о неточности

Опишите, что нужно исправить. Если есть источник, добавьте ссылку.

Вы покидаете datool.ru

Ссылка ведёт на внешний сайт. datool.ru не отвечает за его содержимое — проверьте адрес, прежде чем вводить пароли или платёжные данные.

Переход через 10 с

Перейти