День 1 | Изучаю Rust в NVIM. Введение

День 1 | Изучаю Rust в NVIM. Введение

Предыстория:
Последние несколько лет я пишу в основном на Go. Я считаю что это практически идеальный язык с удобной инфраструктурой и сам синтаксис языка прост, сравним с python или java. Редактор - VS Code, по моему мнению лучшая среда разработки: всё кастомизируется под себя, экосистема расширений покрывает любую задачу

В этом стеке мне комфортно, но я лезу в web3 все таки... и тут возникает проблема

Криптоиндустрия вкладывает огромные усилия в более быстрые исполнительные среды: Move, Solana, параллельные EVM, новые консенсусы - лишь чтобы приблизиться к throughput, который традиционная финсистема получает почти бесплатно из двух SQL-апдейтов в одной БД.

Из-за этой асимметрии на рынке Web3 отмирают медленные языки. Остаются быстрые системные как Rust/C++/C, что даёт контроль над памятью и предсказуемую производительность

Значит, нужно учить Rust. И я решил полностью вылезти из зоны комфорта. Не просто новый язык - это новое начало. Rust в NVIM. Это будет больно, но мне в кайф


Шаг 1 - NVIM настройка

Проблема N1 - у меня windows, уже это дает сильный даунгрейд моих возможностей с работой с nvim. Перейти на линукс очень хочется, но мое железо не позволяет мне этого сделать... Поэтому я пошел простым путем - WSL и консоль для удобства Hyper

Проблема N2 - у меня windows. А nvim строит собственный буфер для копирования и вставки, что крайне не удобно при обучении. Решение было найдено - win32yank. Он пробрасывает windows буфер и nvim самостоятельно подхватит его как clipboard-провайдер

curl -sLo /tmp/win32yank.zip https://github.com/equalsraf/win32yank/releases/latest/download/win32yank-x64.zip
unzip -p /tmp/win32yank.zip win32yank.exe > /tmp/win32yank.exe
chmod +x /tmp/win32yank.exe
sudo mv /tmp/win32yank.exe /usr/local/bin/

Обе проблемы решены теперь можно приступать к настройке самого nvim (урааа!)

Пустой nvim уже имеет в себе очень большой функционал возможностей. Но для меня как эстета и казуала, хочется хотя-бы немного удобства и схожести со VS Code. Есть два пути - LazyVim и kickstart.nvim. kickstart - это один файл init.lua с разумными дефолтами, который ты читаешь целиком и понимаешь каждую строчку. LazyVim - это полноценный фреймворк с десятками плагинов из коробки, который "просто работает", но что именно там работает - чёрный ящик . Угадайте что я выбрал? Конечно же сложный путь - kickstart, мне кажется это даст мне больше понимания nvim и облегчит мне работу в будущем

И так мой сетап выглядит:

нуууу норм?

ничего выдающегося, просто nvim...

Шаг 2 - Rust Basics

Я не стал искать никакие курсы или что-то подобное, я просто выбрал учить раст по ее оффицальной книге, она достаточно интересная и покрывает основной материал, Rust очень интересный язык - это сочетание Haskell, C++ имеет свой странный синтаксис который я еще не видел, главное отличие в сокращении его, то есть int_32 -> i32 и тд.

Пока что дочитал до Ownership в принципе ничего сложного есть 3-и правила:

1) Each value in Rust has an owner.
2) There can only be one owner at a time.
3) When the owner goes out of scope, the value will be dropped.

Легче всего показать на примере из книги:

{                      // s is not valid here, since it's not yet declared
    let s = "hello";   // s is valid from this point forward

    // do stuff with s
}                      // this scope is now over, and s is no longer valid

Но тут возникает прикол, если передал ownership в функцию, то после исполнения переменная вызавет drop и код снизу выдаст ошибку:

fn main() {
    let s = String::from("hello");  // s comes into scope

    takes_ownership(s);             // s's value moves into the function...
    println!("{:?}", s);                                // ... and so is no longer valid here

    let x = 5;                      // x comes into scope

    makes_copy(x);                  // Because i32 implements the Copy trait,
                                    // x does NOT move into the function,
                                    // so it's okay to use x afterward.

} // Here, x goes out of scope, then s. However, because s's value was moved,
  // nothing special happens.

fn takes_ownership(some_string: String) { // some_string comes into scope
    println!("{some_string}");
} // Here, some_string goes out of scope and `drop` is called. The backing
  // memory is freed.

fn makes_copy(some_integer: i32) { // some_integer comes into scope
    println!("{some_integer}");
} // Here, some_integer goes out of scope. Nothing special happens.

Чтобы этого избежать, используются ссылки — &T. В Rust это называется borrowing. Под капотом это указатель, но на уровне системы типов — гарантия проверенного компилятором инварианта: пока ссылка жива, владелец не может быть инвалидирован, и data race на этапе компиляции невозможен.

Мне очень понравилось объяснение:

We call the action of creating a reference borrowing. As in real life, if a person owns something, you can borrow it from them. When you’re done, you have to give it back. You don’t own it.

Есть так-же мутабеьные и имутабельные ссылки.
И на оба действует XOR правило:

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

Вот несколько примеров для понимания:

let mut s = String::from("hello");

let r1 = &mut s;
let r2 = &mut s; // Упадет

println!("{r1}, {r2}");
let mut s = String::from("hello");

{
    let r1 = &mut s;
} // r1 goes out of scope here, so we can make a new reference with no problems.

let r2 = &mut s; // все окей
    let mut s = String::from("hello");

    let r1 = &s; // no problem
    let r2 = &s; // no problem
    let r3 = &mut s; // BIG PROBLEM

    println!("{r1}, {r2}, and {r3}");

Но хочу заметить что в новой версии borrow checker более умный и если референс не используется в дальнейшем, он делает сразу дроп, не нужен новый scoup (вот эти штучки - {code})

let mut s = String::from("hello");

let r1 = &s; // no problem
let r2 = &s; // no problem
println!("{r1} and {r2}");
// Variables r1 and r2 will not be used after this point.

let r3 = &mut s; // no problem
println!("{r3}");

Вооот пока на этом все, продолжу свое обучения языка в следующей части, а пока ПОКААААА