Когда я впервые услышал о Rust, меня зацепил слоган «близкий к С по производительности, но безопасный по умолчанию». С моим 10-летним опытом разработки на разных языках я видел много компромиссов: либо быстро, либо безопасно. Оказалось, Rust делает серьёзную заявку на сочетание этих качеств без привычных для «низкоуровневых» языков проблем вроде утечек памяти и гонок данных. Хочу поделиться своими впечатлениями и рассказать, за счёт чего Rust действительно помогает писать быстрый и безопасный код.


Зачем Rust?

1. Контроль над памятью без «ручного» управления

В языках вроде C или C++ мы вручную контролируем выделение и освобождение памяти. Это гибко, но таит в себе массу ошибок: утечки, двойное освобождение, использование невалидных указателей. В высокоуровневых языках, где есть сборщик мусора (Java, C#, Go), от этих проблем мы уходим, но платим за это дополнительными накладными расходами и иногда непредсказуемыми задержками, когда сборщик мусора решает «подчистить».

Rust предлагает «выделение на стеке и куче» с жёсткой системой контроля владения (ownership) и заимствования (borrowing). Код по-прежнему работает быстро и без сборщика мусора, но при этом большинство ошибок, связанных с памятью, отлавливаются на этапе компиляции.

2. Безопасность на уровне типов

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

3. Производительность

Rust генерирует код на уровне низкоуровневого C/C++. При правильном использовании он даёт схожую производительность, а иногда и превосходит аналоги за счёт более безопасных оптимизаций. Это делает язык отличным выбором для системного программирования, высокопроизводительных сервисов и встроенных систем.


Основные концепции языка

Система владения (Ownership) и заимствования (Borrowing)

Всякий раз, когда мы создаём переменную, Rust назначает ей «владельца». После выхода владельца из области видимости (scope), память автоматически освобождается. Это базовая идея, которая исключает проблему «кто отвечает за освобождение ресурсов».

  • Владелец (Owner): переменная, которая отвечает за ресурс.

  • Заимствование (Borrow): когда мы хотим временно использовать ресурс, принадлежащий другому владельцу. Rust различает «заимствование с возможностью изменения» (mutable borrow) и «только чтение» (immutable borrow). Правило: в один момент времени может существовать только один изменяемый заимствователь или любое количество неизменяемых.

Пример, иллюстрирующий правила владения и заимствования:

fn main() {
 let s1 = String::from("Hello");
// Здесь ownership передаётся в функцию, и s1 больше не доступна
let length = calculate_length(s1);

// Попытка использовать s1 после передачи права собственности
// приведёт к ошибке компиляции: borrow of moved value: `s1`
// println!("Length of s1 is {}", length);
}

fn calculate_length(s: String) -> usize {
 let length = s.len();
 length
 }

Чтобы не терять s1 при передаче в функцию, мы можем «заимствовать» её, передавая ссылку:

fn main() {
let s1 = String::from("Hello");
let length = calculate_length(&s1); // &s1 - заимствование (immutable borrow)
println!("String: {}, length: {}", s1, length);
}

fn calculate_length(s: &String) -> usize {
s.len()
}

Таким образом, s1 остаётся валидной и после вызова функции, а память не копируется — всё работает быстро и безопасно.

Управление временем жизни (Lifetimes)

В Rust компилятор следит не только за тем, кто владеет ресурсом, но и как долго ссылка может жить. Это исключает опасность висящих указателей, когда кто-то ссылается на уже освобождённую память.

fn main() {
let r;
{
let x = 5;
r = &x;
}
// x выходит из области видимости, ссылка r становится недействительной
// println!("r: {}", r); // Ошибка: x не живёт достаточно долго
}

Компилятор нам не даст скомпилировать такую программу. Несмотря на кажущуюся сложности, правила времени жизни (lifetime annotations) быстро становятся понятными и заставляют программиста явно указывать, как организовано «время жизни» переменных.

Безопасная работа с многопоточностью

Rust решает проблему «гонок данных» на уровне системы типов. Код, в котором две нити пытаются одновременно менять одну и ту же переменную без синхронизации, попросту не скомпилируется. При этом язык предоставляет удобные примитивы для конкурентности: std::thread, std::sync, std::sync::mpsc (каналы), async/await для асинхронности.

Простой пример многопоточного кода:

use std::thread;

fn main() {
 let data = vec![1, 2, 3, 4, 5];
// move передаёт владение в замыкание, так что в главной функции data
// уже нельзя использовать
let handle = thread::spawn(move || {
    for i in &data {
        println!("From thread: {}", i);
    }
});

// Если попытаться здесь использовать data, будет ошибка компиляции
// println!("{:?}", data);

handle.join().unwrap();
}

Результат — безопасный многопоточный код без гонок. Если бы мы попытались передать data в несколько потоков без синхронизации, Rust не дал бы это сделать.


Конкретные примеры и особенности

Пример: быстрая обработка данных

Допустим, нам нужно обработать большой список чисел и вывести только те, которые делятся на три. На C/C++ мы бы вручную возились с итераторами, на высокоуровневых языках — писали бы что-то вроде фильтра, но платили бы за «абстракции». В Rust мы можем комбинировать итераторы, сохраняя высокую производительность:

fn main() {
 let data = (1..100_000_000).collect::>();
let count = data
    .iter()
    .filter(|&x| x % 3 == 0)
    .count();

println!("Numbers divisible by 3: {}", count);
}

Компилятор способен эффективно оптимизировать цепочки итераторов (в том числе за счёт «ленивых» вычислений, если мы не сразу собираем результат). При этом у нас нет риска «попасть» на лишние копирования, как это может случиться в некоторых высокоуровневых языках.

Пример: работа с Result и устранение ошибок на этапе компиляции

Rust не имеет исключений (exceptions) в привычном смысле, вместо этого ошибки обрабатываются через тип Result<T, E>. Это вынуждает явно «разбираться» с ошибками:

use std::fs::File;
 use std::io::Read;
fn main() -> std::io::Result<()> {
 let mut file = File::open("data.txt")?;
 let mut contents = String::new();
 file.read_to_string(&mut contents)?;
println!("File contents: {}", contents);
Ok(())
}

Знак вопроса ? упрощает работу: если функция возвращает Result, ? либо «распаковывает» успешное значение, либо немедленно возвращает ошибку в вызывающую функцию. В результате код выглядит аккуратно, и мы не забываем обработать возможную ошибку File::open.

Пример: шаблоны (Generics) и трейты (Traits)

Трейты в Rust — это аналог интерфейсов, а generics позволяют писать универсальный код, не теряя производительности. При компиляции Rust «мономорфизирует» функции, подставляя нужный тип.

fn largest(list: &[T]) -> T {
 let mut max = list[0];
 for &item in list.iter() {
 if item > max {
 max = item;
 }
 }
 max
 }

fn main() {
 let numbers = vec![10, 50, 30, 100, 80];
 println!("Largest number is {}", largest(&numbers));
let chars = vec!['y', 'm', 'a', 'q'];
println!("Largest char is {}", largest(&amp;chars));
}

Здесь largest работает и с числами, и с символами. При этом в каждом конкретном вызове компилятор «подставит» нужные типы. Это не влияет на производительность, потому что всё происходит на этапе компиляции, а не во время выполнения.


Где используют Rust

  • Системное программирование: написание драйверов, операционных систем или низкоуровневых системных утилит.

  • Веб-сервисы: высокопроизводительные серверные приложения, в том числе асинхронные, благодаря фреймворкам вроде Actix или Rocket.

  • Криптография и блокчейн: здесь критически важна безопасность и скорость. Rust хорошо подходит для реализации криптопроtokолов.

  • Игровая индустрия: движки на Rust, интеграция с графическими библиотеками.

  • CLI-инструменты: Rust часто выбирают для утилит командной строки, где важна скорость и надёжность.


Подводные камни и личные впечатления

  1. Порог вхождения
    Rust требует «правильного» мышления об ownership/borrow, lifetimes. Первые недели я регулярно злился на компилятор, который не давал сделать, казалось бы, очевидные вещи. Зато потом приходишь к осознанию, что ошибки он отлавливает не потому, что «придирается», а потому что реально защищает от багов.

  2. Компилятор «знает лучше»
    Строгость языка в долгосрочной перспективе оборачивается благом. Вместо того чтобы отлаживать мистические краши в рантайме, вы исправляете проблемы во время компиляции, когда всё проще воспроизвести и понять.

  3. Размер экосистемы
    Много библиотек (crate’ов) доступно в официальном репозитории (Crates.io). Для многих типичных задач решение уже есть. Но в некоторых нишах экосистема пока не такая зрелая, как в C++ или Python, и придётся писать что-то самостоятельно.

  4. Сборка и зависимые библиотеки
    Build-система Cargo удобна, но вместе с зависимыми библиотеками всё может сильно разрастаться. Иногда придётся понимать, как скомпоновать native-зависимости (особенно на Windows или при кросс-компиляции). Однако Cargo в целом делает процесс сборки куда более приятным, чем во многих других языках.

  5. Асинхронность
    В Rust асинхронный код не работает «из коробки» так просто, как в JavaScript. Нужно подключить runtime (например, Tokio) и разбираться с async/await. Но результат того стоит: вы получаете высокую производительность без проблем, связанных с небезопасностью потоков.


Заключение

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

Если вы только начинаете знакомство с Rust, рекомендую не пугаться первых ошибок компиляции. Со временем вы научитесь «мысленно» распределять владение и время жизни объектов, а компилятор станет вашим надёжным союзником, вылавливающим мелкие недочёты ещё до запуска программы. Развивайтесь в этом направлении, и вы почувствуете, как Rust даёт уверенность, что ваш код и быстрый, и защищённый от большинства «классических» ошибок на уровне конструкции языка.

Комментарии (65)


  1. flx0
    19.02.2025 03:30

    Опять невычитанная гопота. Зачем вы это постите?


    1. lazy_val
      19.02.2025 03:30

      Для менеджера по контенту вполне себе годная статья ))

      Похоже на перевод без указания оригинала


  1. sergio_nsk
    19.02.2025 03:30

    В языках вроде C или C++ мы вручную контролируем выделение и освобождение памяти.

    Не знаешь ты C++.

    на уровне низкоуровневого C/C++

    Садись, два! Как же вы достали. Нет такого языка программирования C/C++. Это два абсолютно разных языка программирования, совместимых на очень узком подмножестве синтаксисов. И С++ ни разу не низкоуровневый язык.

    Дальше автор не осилил блоки кода в редакторе.

    // Попытка использовать s1 после передачи права собственности
    // приведёт к ошибке компиляции: borrow of moved value: `s1`
    // println!("Length of s1 is {}", length);

    Здесь наврал, println!("Length of s1 is {}", length); уcпешно скомпилируется.

    На C/C++ мы бы вручную возились с итераторами, на высокоуровневых языках — писали бы что-то вроде фильтра, но платили бы за «абстракции».

    В С нет итераторов. В C++ не нужны итераторы для этого. Не лез бы ты туда, чего не знаешь.

    Почему растисты так любят сравнивать ржавчину с C++, какая-то одержимость, и часто садятся в лужу? Да потому что их уровень - это C с классами, поэтому у них в сравнениях возникает несуществующий C/C++. Писал бы просто про сильные стороны Rust и не лез, туда, где полный ноль.


    1. qwerty19106
      19.02.2025 03:30

      Автор не пишет на С, С++ и Rust тоже. Вероятно это вообще нейросеть писала. И такие статьи сделают антирекламу любому языку.

      Но зачем вы набрасываете на всё сообщество Rust?


    1. oreym
      19.02.2025 03:30

      Уверен что плюсы не низкоуровневые?)))


      1. Dewblass
        19.02.2025 03:30

        А вы уверены что низкоуровневый ? Вы посмотри на ASM(любой) или BCPL и насладитесь низкоуровневыми языками .


    1. DarkTranquillity
      19.02.2025 03:30

      Коллега, неистово плюсую.

      Иногда кажется, что раст продвигают те, кто не осилил С++.

      Либо любители стильного, модного и молодёжного.

      Плохо то, что у раста сильное лобби, которое пролезло даже в говерменты США.


  1. ednersky
    19.02.2025 03:30

    В языках вроде C или C++ мы вручную контролируем выделение и освобождение памяти.

    а в Rust ручных манипуляций, связанных с памятью, мы делаем в десятки или сотни раз больше. Буквально в каждой строке возимся с этой самой памятью, чтобы "сделать компилятор счастливым".

    Всякий кто пробовал программировать на Rust мог убедиться, что количество усилий по возне с памятью по сравнению с C возросло настолько, что если просто в C быть чуточку внимательнее, то там слёту будет более безопасный код, чем на Rust. При вдесятеро меньших усилиях чем на Rust.

    как-то так :)


    1. qwerty19106
      19.02.2025 03:30

      С С++ сравнение конечно неправильное. Но может быть вы слышали про RAII, которое есть в С++ и Rust, но нет в С? Только это делает на С в 10 раз больше возни с памятью.


      1. ednersky
        19.02.2025 03:30

        RAII есть в С++ как паттерн. А ещё в С++ есть темплейты, ООП. Есть возможность писать на С. Ещё прямая связь с asm и так далее.

        То, что одну из библиотек/подходов выделили в самостоятельный язык - ну да, но то сомнительное превосходство.

        которое есть в С++ и Rust, но нет в С?

        и что с того?

        Только это делает на С в 10 раз больше возни с памятью.

        нет. в Rust возни с памятью больше чем в С. Ибо в С я возню с памятью могу сгруппировать в двух функциях и радоваться этому. А в Rust я в каждой (КАЖДОЙ!) строке должен помнить о памяти. Эта хреновина про "владение" заставляет это делать.

        Rust - это язык, заставляющий (методом садистских пыток) программиста постоянно помнить о памяти. Компилятор постоянно кричит программисту: "я не знаю что делать с памятью! Ты должен, обязан мне помочь!"

        И программирование на Rust - это "телодвижения по осчастливливанию компилятора".

        • Одни люди заводят кошечку. Гладят её: кошечке - удовольствие и человеку удовольствие.

        • Другие люди занимаются садо-мазо сексом. Господину или госпоже - садистское удовлетворение, тебе - боль и от этого... удовольствие.

        • Третьи люди программируют на Rust. Компилятору - садистское удовлетворение, тебе - боль и от этого... удовольствие.

        Что сказать? Ну мир так устроен. Разные люди - разные перверсии.


        1. qwerty19106
          19.02.2025 03:30

          В С вы забудете вызвать одну из этих двух функций, и будет баг на миллион баксов. А RAII вставит вызов автоматически.

          Можно обсуждать другие аспекты языка, но как можно говорить, что RAII не нужен??


          1. ednersky
            19.02.2025 03:30

            В С вы забудете

            а в Rust вы перепутаете плюс с минусом?

            миллион или миллиард различных "Вы забудете" Rust не решает, а вот одну "решает" методом насилия над программистом. И что, хорошо это?


            1. qwerty19106
              19.02.2025 03:30

              Кроме прикольных картинок, будет аргументация про RAII?


              1. ednersky
                19.02.2025 03:30

                аргументацию выше Вы скипнули

                RAII в с++ лучше чем в Rust

                почему? потому что в С++ от него при необходимости можно отказаться


                1. qwerty19106
                  19.02.2025 03:30

                  1) Зачем от него отказываться?
                  2) Расскажите как это сделать?


                  1. ednersky
                    19.02.2025 03:30

                    Зачем от него отказываться?

                    TMTOWTDI - способ выбрать наиболее лаконичную реализацию.

                    зачем нужен поиск лаконичности? чтобы ДРУГИЕ ПРОГРАММИСТЫ могли разобраться. Чтобы им было легче.

                    Это подвариация KISS.

                    Расскажите как это сделать?

                    Просто. не использовать, а вернуться к new/delete, например.


                    1. qwerty19106
                      19.02.2025 03:30

                      RAII не только про освобождение памяти, но и про деструкторы.

                      И таким способом я и в Rust могу явно написать std::free(a), и даже иногда это делаю. Но не вижу смысла спускаться на уровень С постоянно. Так что признайте что были не правы.

                      Rust - это язык, заставляющий (методом садистских пыток) программиста постоянно помнить о памяти. Компилятор постоянно кричит программисту: "я не знаю что делать с памятью! Ты должен, обязан мне помочь!"

                      Теперь аргументируйте это. Может быть приведете пример, разберем его.


                      1. ednersky
                        19.02.2025 03:30

                        RAII не только про освобождение памяти, но и про деструкторы.

                        ну и? Деструкторы - это прежде всего про освобождение памяти. Если попутно с этим можно закрыть файл (например), то это именно попутная функциональность.

                        если сравнивать с Си, то у Си, например, есть оператор goto, который весьма удобен именно в коде про освобождение памяти и закрытие файлов. А в rust - садо и мазо, поэтому goto в Rust нет.

                        Может быть приведете пример, разберем его.

                        let s1 = String::from("hello");
                        let len = calculate_length(&s1);

                        Впрочем, судя по Вашему настрою, Вы не оцените мой пример, но он означает именно то, о чём я говорил :)


                      1. mayorovp
                        19.02.2025 03:30

                        Ну и где в вашем примере программисту нужно помнить о памяти?


                      1. ednersky
                        19.02.2025 03:30

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

                        https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html


                      1. mayorovp
                        19.02.2025 03:30

                        Я знаю Rust и эту главу, но всё равно не понимаю что вы пытаетесь сказать.


                      1. ednersky
                        19.02.2025 03:30

                        давайте к началу вернемся

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

                        Вы возражали.

                        так вот, то что в примере — оно именно про это. Даже чтоб посчитать длину строки или сложить числа Вы должны постоянно держать в уме вопрос: «А где память освободится?»

                        и это всего первый паттерн или кривой замут на эту тему, просто он самый частотный.


                      1. mayorovp
                        19.02.2025 03:30

                        так вот, то что в примере — оно именно про это. Даже чтоб посчитать длину строки или сложить числа Вы должны постоянно держать в уме вопрос: «А где память освободится?»

                        А что случится, если я не буду держать в уме этот вопрос?

                        Вот смотрите, я написал ваш код и ни разу не подумал "А где память освободится?":

                        let s1 = String::from("hello");
                        let len = calculate_length(&s1);
                        

                        ЧЯДНТ?


                      1. ednersky
                        19.02.2025 03:30

                        Вот смотрите, я написал ваш код и ни разу не подумал "А где память освободится?":

                        вы не подумали, автор примера подумал, написав &s1

                        То, что вот это "подумал" вбито (садистскими ухищрениями) уже на подкорку, в уровень привычки, не отменяет того, что это есть.

                        И не отменяет того, что временами это сильно мешает.


                      1. mayorovp
                        19.02.2025 03:30

                        Ну так значит это ваша личная проблема, избавляйтесь от подобной "подкорки". Нет ни единой причины считать, что оператор взятия ссылки для передачи ниже по стеку требует думать про освобождение памяти.

                        И особенно нет причин думать об этом в Rust, но не думать об этом в Си.


                      1. ednersky
                        19.02.2025 03:30

                        Ну так значит это ваша личная проблема, избавляйтесь от подобной "подкорки". Нет ни единой причины считать, что оператор взятия ссылки для передачи ниже по стеку требует думать про освобождение памяти.

                        Вы пишете этот оператор потому, что вам требуется думать про освобождение памяти.

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

                        И особенно нет причин думать об этом в Rust, но не думать об этом в Си.

                        в программах Си, как правило, работу с памятью где-то централизуют, в пределах одного-двух модулей на один проект, а остальные части программ пишут, не задумываясь о том, что это управление памятью где-то есть.

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

                        именно поэтому этим языком пользуются в основном фанатики. Потому что это иррационально: "Я загоню себя в тюрьму, которая будет приучать меня к строго одной и той же дисциплине и на этом пути познаю дзен!"


                      1. mayorovp
                        19.02.2025 03:30

                        Ну наконец-то стало ясно о чём вы вообще пишете.

                        Вы пишете этот оператор потому, что вам требуется думать про освобождение памяти.

                        Нет, я пишу этот оператор потому что мне нужно передать переменную по ссылке.

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

                        Нет, будет ошибка типизации, потому что ожидалась &str, а передана была String. Впрочем, даже если случится то о чём написали вы - будет всего лишь другая ошибка компиляции.

                        в программах Си, как правило, работу с памятью где-то централизуют, в пределах одного-двух модулей на один проект

                        Пожалуйста, приведите пример такой программы...


                      1. ednersky
                        19.02.2025 03:30

                        Нет, будет ошибка типизации, потому что ожидалась &str

                        Если Вы пишете не понимая, или не желая понимать "почему здесь так?", то это не отменяет объяснения "почему здесь именно так".

                        Пожалуйста, приведите пример такой программы...

                        постгрис, майскл, тарантул, редис, да любой большой проект.


                      1. mayorovp
                        19.02.2025 03:30

                        А кто сказал что я не понимаю "почему здесь так"? Но понимать и задумываться - вещи совершенно разные.

                        постгрис

                        230 упоминаний одного только malloc. Что-то не вижу никакой особой централизации работы с памятью в одном месте.


                      1. ednersky
                        19.02.2025 03:30

                        230 упоминаний одного только malloc

                        Там больше, на самом деле - более 1300 запросов malloc/calloc. Но на какой это объём? - более 1.5 млн строк кода на C.

                        понимаете разницу: 0.1% против 50%?


                      1. qwerty19106
                        19.02.2025 03:30

                        Значит вы утвержаете, что оператор goto удобнее деструкторов и RAII? No comments..

                        Впрочем, судя по Вашему настрою, Вы не оцените мой пример, но он означает именно то, о чём я говорил :)

                        Так где в этом примере компилятор постоянно кричит программисту: "я не знаю что делать с памятью?, как вы утверждаете.


                      1. ednersky
                        19.02.2025 03:30

                        Значит вы утвержаете, что оператор goto удобнее деструкторов и RAII? No comments..

                        я утверждаю что goto оператор может быть удобнее деструкторов и RAII. Код Linux ядра тому доказательство.


                      1. qwerty19106
                        19.02.2025 03:30

                        То что в С таким способом эмулируют RAII и ООП не доказывает удобность и полезность goto. Он удобен только для вызова деструктора одного объекта.

                        Если же вам нужно освобождать 2 и более, то код превращается в неподдерживаемую и нечитаемую лапшу из смеси if и goto. Ни в одном современном языке нет goto, как вы думаете почему?)

                        А второй мой вопрос вы совершенно случайно проигнорировали.


                      1. ednersky
                        19.02.2025 03:30

                        как раз goto очень удобен именно тогда, когда нужно освобождать 2 и более ресурсов в строго том же порядке, в котором они взяты.


                      1. mayorovp
                        19.02.2025 03:30

                        Ага, только приходится на каждый из них выделять по отдельной метке, либо расплачиваться в рантайме лишними проверками (ну и порядок, наверное, всё-таки имелся в виду обратный).


                      1. ednersky
                        19.02.2025 03:30

                        заставить RAII освободить список ресурсов в строгом порядке - это тоже не баран чихнул задачка.

                        а goto даёт не только лаконичность, но и наглядность этого самого порядка


                      1. mayorovp
                        19.02.2025 03:30

                        заставить RAII освободить список ресурсов в строгом порядке - это тоже не баран чихнул задачка.

                        Так произвольный порядок и не нужен, нужен корректный порядок. А он обычно именно тот, в котором RAII освобождает ресурсы.


                      1. ednersky
                        19.02.2025 03:30

                        корректный и есть строгий.

                        ресурсы в ядре взаимозависимы, но оформляются как независимые системы.

                        Просто потому, что так удобнее.

                        и кстати RAII - большой источник секса в асинхронном или многопоточном проггинге.

                        помимо того, что это просто источник секса


                      1. mayorovp
                        19.02.2025 03:30

                        Повторюсь яснее: если вам в принципе требуется думать над тем, в каком порядке будут освобождены ресурсы при использовании RAII - вы используете RAII некорректно.


                      1. ednersky
                        19.02.2025 03:30

                        да понимаю я, понимаю. Что если компилятор счастлив а я нет - я дурак,

                        а если компилятор не счастлив, то я снова дурак.

                        такая жизнь с этим вашим компилятором


                      1. qwerty19106
                        19.02.2025 03:30

                        А если иногда 2, а иногда один? В конструкторах такое сплошь и рядом. Будет жуткая смесь if и goto, чтобы избавиться от которой и придумали RAII.

                        компилятор постоянно кричит программисту: "я не знаю что делать с памятью?

                        И еще раз задам тот же вопрос: где в этом примере компилятор так делает?


                      1. ednersky
                        19.02.2025 03:30

                        А если иногда 2, а иногда один?

                        дык загляните в Linux-src

                        там как раз этот паттерн "иногда от 1 до 10" прямо постоянно встречается.

                        И еще раз задам тот же вопрос: где в этом примере компилятор так делает?

                        в ошибках. забыл про память - сразу не скомпилировалось.


                      1. qwerty19106
                        19.02.2025 03:30

                        Заглянул. Смесь if и goto. Но чаще просто куча if. Что и требовалось доказать.

                        в ошибках. забыл про память - сразу не скомпилировалось.

                        Вы сами то свой пример запускали?
                        1) Если calculate_length принимает ссылку, то ей вообще пофиг на память. Как и в С.
                        2) Если calculate_length принимает владение, то она сама вызовет деструктор и освободит память. И это абсолютно ясно из синтаксиса языка (как с этим в С, а?) А компилятор за программиста это проверит, и убедится что дальше s1 никто не использует.

                        А вот в С вам придется в документации к функции написать, что она внутри освобождает переданную в нее память. И ни какими средствами языка С это не объяснить компилятору, из чего сразу вылезет Use After Free, Double Free и прочие UB.

                        Если бы вы почитали Линуса Торвальдса, то узнали бы что это один из основных его аргументов за Rust. Он хочет больше Compile-Time проверок в коде. Язык С этого не может.


                      1. ednersky
                        19.02.2025 03:30

                        Если бы вы почитали Линуса Торвальдса, то узнали бы что это один из основных его аргументов за Rust

                        а ещё в ядре Linux присутствует Lua, который куда более чем Rust удобнее. Как раз потому, что там нет типов и всей вот этой компиляторной чепухи.


                      1. qwerty19106
                        19.02.2025 03:30

                        Что же вы не хотите обсуждать свой же пример? Уводите диалог куда-то в сторону, причем уже 3-й раз. Закрадываются подозрения, что аргументированно ответить нечем!

                        P.S. А давайте писать драйвера на Lua, раз он так хорош.


                      1. ednersky
                        19.02.2025 03:30

                        дык я обсуждаю свой пример, но в ответ я слышу аргументы вида "меня не волнует почему тут ссылка оформлена, мне важно, что компилятор типы проверит".

                        какой смысл тут что-то обсуждать если аргументы отвергаются столь наглым образом?


                      1. qwerty19106
                        19.02.2025 03:30

                        Вот в этом комментарии я подробно расписал случай со ссылкой, и случай с владением. Вы на него ответили ничего.

                        Так будете обсуждать предметно?


                      1. ednersky
                        19.02.2025 03:30

                        ну да и Вы в этом комментарии подтверждаете, что при вызове КАЖДОЙ функции, при использовании внутри КАЖДОГО выражения Вам приходится думать о том, как память будет освобождена и где можно обойтись без ссылок, а где Вы это делать обязаны.

                        именно предметно и обсуждаем. Просто Вы смотрите с широко раскрытыми глазами на код и говорите: Я НЕ ВИЖУ!

                        Ещё раз: Rust заставляет программиста думать о выделении/управлении памяти в каждом выражении, в каждом объявлении функции. И, если программист сумел таки "сделать компилятор счастливым", то он соблаговолит выделить память и потом её освободить.

                        Цель: посадить программиста в тюрьму/клетку, где в каждой строке он обязан думать

                        • о памяти

                        • о типах

                        • об ошибках

                        и дескать тогда, он якобы будет писать качественный код.

                        но в этой парадигме программист становится настолько заторканный, что об алгоритме подумать ему некогда, ибо тот алгоритм оказывается скрыт за всей этой мишурой


                      1. mayorovp
                        19.02.2025 03:30

                        А альтернатива-то какая - вообще не думаете о памяти, типах и ошибках?

                        Вы точно сишник? Надеюсь, вы никогда не будете писать ничего критичного...


                      1. ednersky
                        19.02.2025 03:30

                        А альтернатива-то какая - вообще не думаете о памяти, типах и ошибках?

                        Ага

                        Вы точно сишник?

                        В данный момент я сишник и луашник. Низкий уровень мы пишем на Си, но как только производительность перестаёт требовать - переходим к клею на Lua.

                        Есть сильные пересечения с Go и небольшие с Rust.

                        Надеюсь, вы никогда не будете писать ничего критичного...

                        Ну... может быть, базы данных - это не так уж и критично ;) Но пишем мы именно их.


                      1. qwerty19106
                        19.02.2025 03:30

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

                        Я НЕ ВИЖУ!

                        Нельзя увидеть то чего не существует.

                        И вы опять написали целую простыню текста, но как же разбор примера? Где обсуждение ссылок, указателей, деструкторов и т.д.? Опять ничего!


                      1. ednersky
                        19.02.2025 03:30

                        вот вот:
                        "Я не вижу!"

                        "Опять ничего!"

                        Разговор с Вами напоминает анекдот:

                        Отец и сын стоят на берегу моря.

                        - Вот, сынок, это море.

                        - Где?

                        - Вот это, уходящее в небо, голубое пространство, все это море...

                        - Где?

                        - Видишь, волны играют, чайки снуют туда-сюда, блики от солнца, в дали белый пароходик, запах, непередаваемый запах!... Все это - море!

                        -Где?

                        Отец психует, хватает сына за загривок и несколько раз макает его башкой в воду:

                        - Вот море! Вот море! Вот море! Вот море! Вот море! Вот море!

                        - Ой, папа, что это было?!

                        - Море, сынок...

                        -Где?


                      1. mayorovp
                        19.02.2025 03:30

                        Да, именно так разговор и выглядит... только вот происходит он в 100 километрах от берега.


                      1. qwerty19106
                        19.02.2025 03:30

                        Я вам пишу про ссылки, указатели, деструкторы, RAII.

                        А вы в ответ веселые картинки и анекдоты. А вы точно программист вообще?

                        P.S. Я вас не минусую. Но отлично понимаю за что минусуют другие.


                      1. ednersky
                        19.02.2025 03:30

                        и я Вам пишу про ссылки, указатели, деструкторы, RAII.

                        Вот для чего нужны деструкторы? Чтобы освобождать занятые ресурсы. Чаще всего память, значительно реже - связанные с памятью, вроде "закрытия хендлов".

                        Соответственно зачем этот RAII задуман? RAII - это паттерн работы с этой самой памятью. И при этом это всего лишь один из паттернов.

                        В Rust этот паттерн взят за базисный. Помогает это? Чему?

                        написанию алгоритмов так вредит, ибо помимо алгоритма пользователь вынужден постоянно думать об освобождении этой самой памяти. Ну вот на том RAII и стоит, чтоб заставлять пользователя постоянно об этом помнить. Методика ведь сводится к тому, что "если ты будешь постоянно об этом думать, то результат точно будет".

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


                      1. qwerty19106
                        19.02.2025 03:30

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

                        Так RAII сам вызовет деструктор и освободит память. Именно по-этому программист может не думать об освобождении памяти. И не думает, возьмите любой код на С++, и поищите там вызов delete для unique_ptr например.

                        А без RAII вам нужно вручную вызвать деструктор и освободить память. Очевидно что в этом случае нужно думать о памяти:

                        {
                        A* a = malloc(sizeof(A));
                        init(a);
                        ...

                        destruct(a);
                        free(a);

                        }

                        против

                        {
                        let a = Box::new(A::new());
                        ...
                        }

                        В С++ тоже будет одна строчка.


                1. mayorovp
                  19.02.2025 03:30

                  Что вы понимаете под "отказаться от RAII" и почему точно так же нельзя при необходимости сделать в Rust?


                  1. ednersky
                    19.02.2025 03:30

                    понимаю: писать код, не использующий RAII, но на Rust от этой парадигмы отказаться нельзя


                    1. qwerty19106
                      19.02.2025 03:30

                      Вы опять утверждаете, что это в Rust это не возможно. Хотя я еще вчера вам доказал обратное: вызов std::free(a); в Rust полностью аналогичен коду delete a; в С++.


                    1. mayorovp
                      19.02.2025 03:30

                      Так почему отказаться-то нельзя? Если вам оно так мешает - берёте и не используете. В чём проблема-то?


                      1. ednersky
                        19.02.2025 03:30

                        Вы не понимаете разницы между:

                        • TMTOWTDI - находится в разряде "не принято", или даже "отрицается" (как у Python)

                        • TMTOWTDI - инструмент, такой же рядовой, как и RAII

                        ?


                      1. mayorovp
                        19.02.2025 03:30

                        В вашем изложении - нет, не понимаю.


                      1. ednersky
                        19.02.2025 03:30

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

                        (теоретически на F#, кто-то мне на хабре рассказывал, возможно писать мутабельный код. Практически, никто в коммюнити, stdlib этого не делает и подобное поведение считается грехом)

                        Помните историю с автором "самого быстрого http-сервера на Rust"? Так вот, коммюнити его банально затравило и теперь это не самый быстрый и поэтому и не такой популярный http-сервер на Rust.

                        https://habr.com/ru/articles/484436/


                      1. mayorovp
                        19.02.2025 03:30

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


                      1. ednersky
                        19.02.2025 03:30

                        а в чём цель простановки минуса каждому комменту? разве комментария, что вы всё равно пишете, недостаточно?

                        Распирает от несогласия и хочется выразить его дважды?