Почему вы должны попробовать Rust

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

    • Как убедиться, что в моем приложении нет проблем и уязвимостей, связанных с неправильной работой с памятью?

    • Как быть уверенным в том, что любой доступ к общим объектам правильно защищен?

    • Как свести к минимуму любую работу, не связанную напрямую с написанием кода?

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

    История одного языка

    Все началось в 2006 году как персональный проект сотрудника Mozilla - Грейдона Хоара (Graydon Hoare). В 2009 году Грейдон представил свой новый язык программирования коллегам из Mozilla Research, предложив его как перспективную замену C++, поскольку он разрабатывался с приоритетом на безопасность и эффективность создания параллельных приложений (современные браузеры, такие как Mozilla Firefox, являются крупными и очень сложными проектами с не тривиальными алгоритмами параллельной обработки данных). Вскоре, на ежегодном саммите Mozilla 2010, Грейдон представил язык Rust и анонсировал проект Servo (браузерный движок нового поколения). Вначале сообщество разработчиков отнеслось к этой инициативе довольно скептически и некоторые обвиняли Mozilla в синдроме NIH (Not Invented Here). Они назвали его ещё одним бесполезным языком программирования, который умрёт ещё до того, как он станет достаточно популярным, чтобы иметь хоть какое-то значение (вспоминая язык D и его судьбу). Однако дальнейшее развитие событий показало, что это не очередной академический проект для тестирования идей, а полноценный конкурент для таких мастодонтов, как C/C++.

    В 2011 г. Rust, используя LLVM, успешно скомпилировал сам себя, а в 2015 году была выпущена первая стабильная версия 1.0. И, наконец, в 2017 году Mozilla выпустила свой первый полноценный проект, написанный на Rust, который был успешно интегрирован в Firefox - Quantum CSS - полностью мультипоточный CSS-движок, в основу которого взят результат разработки прототипа Servo. На этом этапе Mozilla доказала, что язык Rust уже зрелый и обладает достаточной функциональностью для создания больших и сложных production-ready приложений.

    Прошло уже больше пяти лет с момента первого стабильного релиза. От изначальной версии Rust, показанной на презентации в 2010 году, уже мало что осталось. Полистав ту презентацию, вы можете легко заметить, что тогда язык был совершенно иным: другой синтаксис, зеленые потоки вместо системных и т.д. Rust сильно изменился во всех аспектах и стал языком программирования общего назначения, который подходит для любых задач. Этот результат был достигнут в основном благодаря открытому и дружелюбному сообществу, создавшему инфраструктуру, статьи, книги, учебные пособия и полезные инструменты. В настоящее время Rust можно применять в любой сфере, независимо от того, является ли проект desktop-приложением, ядром ОС или веб-приложением для облачного сервиса.

    В последние годы мнение разработчиков о языке изменилось в положительную сторону. Невероятно, но Rust является самым любимым языком пользователей Stack Overflow уже пять лет подряд! Более того, стали появляться проекты, целиком написанные на Rust, а его присутствие в популярных open-source и коммерческих проектах растет с каждым годом. Например, ripgrep - это проект с открытым исходным кодом для рекурсивного поиска в каталогах с использованием регулярных выражений. Он в 10 раз быстрее, чем GNU grep, и в 4 раза быстрее, чем Silver Searcher. В результате ripgrep был интегрирован в MS Visual Studio Code в качестве средства поиска регулярок по умолчанию. Также, в копилку доказательства хорошей производительности получаемых программ можно добавить результаты The Computer Language Benchmarks Game проекта Debian, где Rust в одной лиге с C/C++.

    Сегодня множество технологических компаний выбирают Rust за его производительность, безопасность и эффективность разработки. Позвольте мне привести несколько примеров:

    • Apple – технологический гигант, который ставит на первое место производительность и безопасность, решил перевести низкоуровневую часть Apple Cloud Traffic на Rust, а новый функционал, по возможности, в первую очередь писать на нем.

    • Amazon – выбрал Rust для реализации Firecracker – проекта безопасных и быстрых microVM для бессерверных вычислений.

    • Microsoft – также активно исследует возможность перехода на Rust для низкоуровневых и чувствительных к производительности компонентов. Они уже попробовали в качестве эксперимента переписать некоторые низкоуровневые системные компоненты Windows.

    • Google – разрешает использовать Rust (кроме kernel части) для реализации своей новой операционной системы Fuchsia.

    • Mozilla – собирается переписать внутренние компоненты на Rust, чтобы улучшить многопоточную обработку, как часть инициативы сделать Firefox более безопасным и быстрым - Firefox Quantum.

    • Huawei – также исследует возможности использовать язык Rust в своих будущих проектах.

    Список можно продолжить и далее: Dropbox, Facebook, Bitbucket, Discord и т.д. – все эти известные компании начали использовать Rust в частях своих серверных платформ. Обратите внимание, что не только крупные международные компании используют Rust – в нем заинтересованы и стартапы. Например, новая компания, основанная Брайаном Кантриллом (изначальный разработчик dtrace), планирует использовать Rust в качестве основного языка для реализации своего проекта. Немаловажно для всех этих компаний то, что разработчики Rust принимают решения, связанные с дизайном языка, руководствуясь обратной совместимостью и стабильностью кодовой базы.

    Но, несмотря на все успехи Rust, колыбель языка Mozilla чувствовала себя не очень хорошо и, в связи с финансовыми трудностями, в 2020 году приступила к отделению проекта в независимую организацию Rust Foundation, серьезно уменьшив свое влияние на развитие языка и отпустив его в свободное плавание. Изначальный список членов организации внушает оптимизм за будущее языка:

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

    Но что делает Rust таким желанным для многих разработчиков? Давайте немного углубимся в детали и изучим некоторые важные и полезные аспекты языка.

    Приоритет безопасности

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

    • Использование памяти после освобождения (Use After Free)

    • Разыменование нулевого указателя (Null Dereference)

    • Использование неинициализированной памяти (Using uninitialized variables)

    • Двойное освобождение (Double Free)

    • Переполнение буфера (Buffer Overflow)

    MSRC Security Research 2019 года (Microsoft) показал, что 70% Common Vulnerabilities and Exposures (CVEs) в их продуктах были связаны с проблемами безопасности памяти в С и С++ (думаю весьма известный график):

    Кто-то может сказать, что данный отчет лишь показывает проблемы Microsoft, так как их продукты являются проприетарным программным обеспечением, тогда как продукт с открытым исходным кодом благодаря контролю «тысячи глаз» будет иметь значительно меньше проблем. На самом деле не все так радужно. Взгляните на CVEs за 2019 год (последний из доступных на данном ресурсе), найденные в ядре Linux, разрабатываемом и проверяемом ведущими отраслевыми экспертами:

    Как мы видим, open-source сообщество допустили достаточно большое количество уязвимостей, связанных с безопасностью работы с памятью (примерно 65%). Я уверен, вы знаете, что такого рода проблемы тяжело найти и зачастую они проходят мимо глаз. Однако в Rust эти проблемы не могут возникнуть, как говорится, by design (если конечно не использовать unsafe, но это тема для отдельного разговора). И все это достигается на этапе компиляции!

    Для этих целей Rust имеет такие элементы языка, как Ownership и Borrowing. Система Ownership является основой для всего языка. Rust гарантирует, что у любого заданного объекта на все время его жизни существует ровно один владелец:

    fn main() {
        let a = String::from("Hello"); // Аллоцируем объект на куче
        let b = a; // меняем владение объектом с a на b
        // let c = a; // Ошибка компиляции
        println!("{}", b); // b теперь владелец строки
    }

    Кроме того, передача объекта в качестве аргумента функции также приведет к передаче права собственности на область действия аргумента функции:

    fn do_smth(a: String) {
        // а владеет объектом
        println!("{}", a);
    }
      
    fn main() {
        let a = String::from("Hello");
        // Переносим объект в область видимости функции
        do_smth(a);
        // let b = a; // Ошибка компиляции
    }

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

    • Объясняет, почему проблема произошла;

    • Выделяет все элементы, которые вызвали проблему;

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

    Для примера, посмотрите на это подробное сообщение об ошибке:

    error[E0382]: use of moved value: `a`
    --> src/main.rs:4:13
    |
    2 | let a = String::from("Hello");
    | - move occurs because `a` has type `std::string::String`, which does not implement the `Copy` trait
    3 | let b = a;
    | - value moved here
    4 | let c = a;
    | ^ value used here after move
    error: aborting due to previous error
    For more information about this error, try `rustc --explain E0382`.

    Хорошо, а когда освободится выделенная память? В Rust нету GC, поэтому волшебный runtime не придет на помощь. В таких языках как C/C++ разработчик обязан самостоятельно определять, когда пора возвратить память ОС. Данная задача не из тривиальных и требует достаточно высокую квалификацию в сложных проектах. Rust решает эту проблему по-своему: он позволяет хранить данные как в стеке, так и в куче, а память автоматически возвращается, как только переменная, которой она принадлежит, уходит за пределы области видимости:

    {
        let s = String::from("hello"); // создаем строку s
        // различные операции над s
    } // С этого момент s вышла за предел области видимости и может быть удалена

    В Rust можно также заимствовать (borrow) объект, используя ссылку, чтобы избежать излишние изменения владельца и копирования. Однако для этого существуют некоторые строгие ограничения, процитирую:

    • В любой момент времени вы можете иметь либо одну изменяемую ссылку, либо любое количество неизменяемых ссылок.

    • Ссылки всегда должны быть актуальными.

    Для этой цели Rust отслеживает время жизни (lifetime) для каждой ссылки. Чаще всего времена жизни объектов генерируются автоматически, но в некоторых случаях мы должны аннотировать их вручную, используя специальный синтаксис языка. Это позволяет эффективно управлять памятью без оверхеда от использования GC. Пример заимствования:

    fn do_smth(a: &String) {
        println!("{}", a); // Немутабельная операция
    }
      
    fn main() {
        let a = String::from("Hello");
        do_smth(&a); // одалживаем объект у a
        println!("{}", a); // a все еще владелец объекта
    }

    А вот так мы можем нарушить озвученные выше ограничения. Но тут приходит borrow checker, и выписывает нам ошибку:

    fn main() {
        let mut s = String::from("hello");
      
        let r1 = &mut s;   
        let r2 = &mut s; // Здесь ошибка компиляции
      
        println!("{}, {}", r1, r2);
    }

    В данном примере мы нарушаем одно из правил языка – в один момент времени разрешена только одна изменяемая ссылка. В этом случае мы получаем следующее сообщение:

    error[E0499]: cannot borrow `s` as mutable more than once at a time
    --> wiki/src/main.rs:5:14
    |
    4 | let r1 = &mut s;
    | ------ first mutable borrow occurs here
    5 | let r2 = &mut s;
    | ^^^^^^ second mutable borrow occurs here
    6 |
    7 | println!("{}, {}", r1, r2);
    | -- first borrow later used here

    Эти ограничения позволяют производить мутации, но в строго контролируемом стиле. Это то, с чем новые разработчики имеют наибольшее количество проблем, потому что такие языки как C/C++ позволяют мутировать объекты без каких-либо ограничений. Все эти правила были введены, чтобы предотвратить одну очень неприятную проблему при разработке многопоточных программ - data race. Но об этом поговорим чуть позже.

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

    • Разделяет переменные на изменяемые и неизменяемые.

    • Каждая переменная является неизменяемой по умолчанию и обязательно должна быть проинициализирована актуальным для данного типа значением (например, определенным значением enum).

    • Не позволяет выполнять неявное приведение типов даже для примитивов.

    • Проверка границ массивов (небольшая цена производительности для исключения более серьезных проблем).

    • В debug-режиме компилируется с проверкой integer overflow.

    Как некоторые говорят, Rust - это весьма педантичный компилятор и эти неудобства могут немного надоедать, увеличивая время вхождения для новичков. Но эти неудобства языка обязательны для обеспечения безопасности работы с памятью. В ответ мы получаем нечто большее - в Rust (опять же, если не использовать unsafe) невозможны упомянутые выше ошибки: использование памяти после освобождения, разыменование нулевого указателя, использование неинициализированной памяти, двойное освобождение и переполнение буфера.

    И под конец главы добавлю, что сами разработчики Rust не только о себе думают, но и активно участвуют в улучшении безопасности проекта LLVM. Например в этом году они в тесной коллаборации с LLVM добавили поддержку защиты от Stack Clash в LLVM/Clang.

    Многопоточность без гонок

    Последние поколения процессоров склонны наращивать количество ядер. Еще несколько лет назад максимальное количество ядер в корпоративных процессорах составляло 28, но не так давно получили распространение процессоры AMD Epyc и Kunpeng, которые подняли планку до 64 ядер! Это огромная мощность, которую очень трудно использовать эффективно. Максимальное использование ресурсов таких CPUs приводит к тому, что алгоритмы и приложения становятся все более сложными. Исторически, программирование в этом контексте всегда было трудоемким и подвержено ошибкам, поэтому разработчикам нужны инструменты, которые помогут им реализовать свои идеи без головной боли.

    Fearless Concurrency - этим термином разработчики Rust называют способность своего языка помогать создавать многопоточные алгоритмы безопасно и эффективно. Давайте начнем с простого примера, как создать поток:

    use std::thread;
      
    fn main() {
        // Создаем поток и запускаем на нем анонимную функцию
        let handler = thread::spawn(|| {
            // Тело функции
            println!("I'm thread");
        });
        // Родительский процесс выполняется здесь
        println!("I'm main thread");
        // Ожидаем пока завершится поток
        handler.join().unwrap();
    }

    В Rust потоки изолированы друг от друга с помощью системы владения объектом. Записи могут происходить только в том случае, если поток является владельцем данных или имеет изменяемую ссылку. Таким образом, в любой момент времени существует только один поток, который имеет мутабельный доступ к данным. Чтобы ограничить передачу данных между потоками, Rust поддерживает два типажа (traits): Sync и Send. Оба этих типажа реализуются автоматически, когда компилятор определяет, что тип данных соответствуют требованиям. И тут мы уже увидели одну очень приятную особенность Rust: язык различает безопасные и небезопасные типы для передачи данных между потоками .

    Send – это типы, которые могут быть безопасно перемещены из одного потока в другой. Например, Arc (Atomic Reference Counter) и String - это типы Send. Один из способов передачи данных между потоками - каналы в стиле Go. Это потокобезопасная операция, и компилятор проверяет, реализует ли объект Send. Вот пример переноса объекта:

    fn main() {
        // Создаем канал на передачи данных
        let (sender, receiver) = channel();
        // Создаем новый поток и передаем туда sender
        thread::spawn(move || {
            // Создаем объект
            let hello = String::from("Hello");
            // Отправляем объект через канал
            sender.send(hello).unwrap();
            // Начиная с этого места, владение объектом передано через канал
            // let tmp = hello; // Ошбика компиляции
        });
        // Получаем данные из канала
        let data = receiver.recv().unwrap();
        // Печатаем строку "Hello"
        println!("{}", data);
    }

    Если разработчик попытается переместить объект, не являющийся объектом Send, в другой поток, используя захват переменной замыканием, компилятор Rust выведет нечто подобное:

    `std::rc::Rc<i32>` cannot be sent between threads safely

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

    fn main() {
        // Создаем объект
        let tmp = 42;
        // Отправляем владение объектом в Arc
        let data = Arc::new(tmp);
        // Создаем новую ссылку на Arc
        let data_ref = data.clone();
        // Создаем поток и запускаем функцию в нем
        let thread = thread::spawn(move || {
            // Разыменовываем объект из Arc и печатаем его
            println!("{}", *data_ref);
        });
        // Печатаем объект
        println!("{}", *data);
        // Синхронизируем потоки
        thread.join().unwrap();
    }

    В случаях, когда требуется потокобезопасная мутабельность, Rust предоставляет атомарные типы данных и исключающую блокировку через Mutex. Основное преимущество подхода Rust - это то, что нет простого способа получить доступ к объекту без блокировки мьютекса или без использования атомарного типа данных. Например, когда вы создаете мьютекс, вы также передаете в него права на собственность объекта. Метод Lock создает некий smart-pointer MutexGuard на объект внутри мьютекса, через который вы можете получить доступ к объекту в этом потоке, пока у MutexGuard не закончится время жизни:

    // Аллоцируем на куче
    let s = String::from("Hello, ");
    // Переносим владение объектом в Mutex
    let mutex = Mutex::new(s);
    // Ошибка: s больше не владелец
    // s.push_str("World!");
    // Блокируем мьютекс и создаем MutexGuard
    let mut d = mutex.lock().unwrap();
    d.push_str("World!");
    // Вывод: Hello, World
    println!("{}", d);
    // MutexGuard освобождается при выходе из области видимости

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

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

    One Tool to Rule Them All

    Что мы узнали: Rust - это уникальный язык, который может сделать жизнь разработчиков программного обеспечения проще (или сложнее), а их программы безопаснее (хотя и требует более долгого времени вхождения до начала эффективного применения). Но есть еще один чрезвычайно важный аспект всех языков программирования, который требует отдельного внимания - инструментарий. Давайте вспомним, какой инструментарий используется в C/C++? На самом деле, на это трудно ответить, потому что каждый проект выбирает свой пакетный менеджер, билд-систему, формат документации и систему тестирования. Это вызывает трудности в обслуживании продуктов у мейнтейнеров.

    Разработчики Rust знают об этой ситуации и понимают, что они должны обязательно предложить нечто лучшее, чтобы обеспечить все необходимые функции и уменьшить трату времени на задачи, которые не связаны непосредственно с разработкой продукта. Результат их работы они назвали Cargo. Cargo поставляется вместе с Rust и используется почти в каждом проекте (хотя без него вы все еще можете использовать компилятор rustc, как любой другой компилятор C/C++). Этот менеджер берет все процедуры обслуживания на себя и помогает вам создавать проекты, управлять зависимостями, собирать приложение, создавать документацию и тестировать проект.

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

    cargo new test-proc

    Cargo создаст каталог со следующими файлами:

    .
    ├── .git
    ├── .gitignore
    ├── Cargo.lock
    ├── Cargo.toml
    ├── src
    └── main.rs

    Как мы видим, Cargo создал git репозиторий, каталог с исходниками, TOML-файл, содержащий конфигурацию проекта, и некоторые служебные файлы. Самый интересный файл TOML. Здесь хранятся все настройки проекта, включая имя проекта, версию, список зависимостей, флаги для компилятора и другие классные вещи. Его легко читать и редактировать, а так же централизовано управлять релизами. Пример содержания файла после инициализации:

    [package]
    name = "test-proc" # Имя проекта
    version = "0.1.0"  # Версия в нотации Semver
    authors = ["hackerman"] # Список авторов
    edition = "2018"   # Версия Rust

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

    fn add(a: u32, b: u32) -> u32 {
        a + b
    }
     
    fn main() {
        println!("Data = {}", add(1, 2));
    }

    И соберём ее:

    cargo build
    Compiling test-proc v0.1.0 (/home/hackerman/projects/test-proc)
    Finished dev [unoptimized + debuginfo] target(s) in 0.38s

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

    Тестирование

    Rust и Cargo уже имеют все, что нужно для написания тестов без каких-либо внешних инструментов. Вкратце, тест в Rust — это функция, аннотированная атрибутом #[test]. Давайте для примера создадим тестовую функцию, добавив несколько строк кода в main.rs:

    // Атрибут для тестовой функции
    #[test]
    // Имя функции это имя теста
    fn it_works() {
        // Тело теста
        assert_eq!(add(2, 2), 4);
    }

    Готово! Теперь запускаем:

    cargo test
    Compiling test-proc v0.1.0 (/home/hackerman/projects/test-proc)
    Finished test [unoptimized + debuginfo] target(s) in 0.53s
    Running target/debug/deps/test_proc-7c55eae116dd19b3
      
    running 1 test
    test it_works ... ok
      
    test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

    С помощью атрибута #[cfg(test)] можно создать отдельный подмодуль со всеми нужными вспомогательными функциями для тестов который будут использоваться только во время тестирования.

    Документация

    Cargo предоставляет продвинутые инструменты для создания интерактивной документации с богатыми возможностями форматирования. Rust имеет особые комментарии (/// - тройная косая черта) для документации, которые известны как комментарии к документации с markdown нотацией, которые будут использоваться для генерации HTML-документов. В этом примере мы добавили некоторую информацию о функции add() и собрали соответствующую документацию:

    /// Sums two values.
    ///
    /// # Examples
    ///
    /// ```
    /// let arg1 = 6;
    /// let arg2 = 1;
    /// let answer = testproc::add(arg1, arg2);
    ///
    /// assert_eq!(add(6, 1), answer);
    /// ```
    fn add(a: u32, b: u32) -> u32 {
        a + b
    }

    И собираем документацию одной простой командой:

    cargo doc
     Documenting test-proc v0.1.0 (/home/hackerman/projects/test-proc)
        Finished dev [unoptimized + debuginfo] target(s) in 0.82s

    В результате мы получаем HTML-страницы с гиперссылками, подсветкой синтаксиса и поисковой системой:

    Внешние зависимости

    В Rust единица компиляции называется "crate" и может быть либо библиотекой, либо исполняемой программой.

    Например, нам нужно проанализировать некоторые JSON-файлы, но мы не хотим делать это с нуля. В этом случае мы идем на постоянно растущий crates.io репозиторий и ищем подходящий crate для нас. Отлично! Мы нашли Serde - библиотека для сериализации и десериализации структур данных. Давайте попробуем импортировать ее с поддержкой json в наш проект с помощью TOML-файла:

    [dependencies]
    serde_json = "1.0.53"

    И вызываем команду сборки проекта:

    > cargo build
       Compiling serde v1.0.110
       Compiling ryu v1.0.4
       Compiling itoa v0.4.5
       Compiling serde_json v1.0.53
       Compiling test-proc v0.1.0 (/home/hackerman/projects/test-proc)
        Finished dev [unoptimized + debuginfo] target(s) in 7.41s

    Cargo проверил все зависимости, загрузил их и собрал. Теперь вы можете пользоваться библиотекой напрямую! Раздел [dependencies] - это место, где вы сообщаете Cargo требуемые крейты и их версии. В этом примере мы задаем семантический спецификатор версии 1.0.53. Cargo понимает Semver нотацию, и это фактически означает "любую версию, совместимый с версией 1.0.53". Для обновления крейтов до новой версии достаточно воспользоваться командой cargo update. Кроме того, любой может поделиться своими собственным крейтом на crates.io, и вы можете это сделать лишь парой команд! С помощью крейтов можно установить дополнительные инструменты в рабочее пространство (например, ripgrep) для различных целей вашего проекта. Вдобавок, вы можете установить свой собственный сервер crate.io в сети вашей организации и быть независимыми от внешних поставщиков. Короче говоря, замечательный инструмент, который делает разработку на Rust такой гладкой и беспроблемной.

    Среды разработки

    Последнее, но не менее важное, о чем я хочу вам рассказать - это rust-analyzer (будущий преемник RLS), предоставляющий поддержку Rust в различных средах разработки. В данный момент, с использованием rust-analyzer или своей собственной реализации анализатора, уже поддерживаются следующие IDE и редакторы: vim, emacs, MS Visual Studio Code, IntelliJ Idea и т.д. Они имеют все необходимые функции для эффективного написания кода, такие как: дополнение кода, вывод документации и подсветка ошибок. Количество поддерживаемых интегрированных сред достаточно велико, чтобы вы могли себя чувствовать, как дома.

    Эпилог

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

    Huawei
    Huawei – мировой лидер в области ИКТ

    Comments 153

      +1
      Интересная штука. Только сходу я не понял 2 вещи:
      • как со всеми этими владениями выглядит, например, процедура вставки в связный список?
      • можно ли с карго использовать не гит, а, например, свн?
        +1

        Со списком все просто — элемент передается списку во владение. По поводу не-гита — вопрос стоит несколько шире, но еще не решен.

          +21

          Связный список технически можно написать на 100% safe Rust на умных указателях. Option<Rc<T>> например. Проверку на None придется везде делать явно, а все, кто ссылается на список, будут получать слабую ссылку (Weak). Для разыменования слабой ссылки ее надо временно проапгрейдить до сильной. Если разрушить такой список, пока кто-то работает с его элементами (классический пример с remove под for each), объекты останутся во временном владении у тех, кто на них ссылается.


          Но на практике так не делают. Для списков и вообще для хитрых алгоритмах на указателях, правильность которых доказана на бумаге, в Rust есть указатели в стиле Си (без проверки области видимости). Разыменование таких указателей возможно только с ключевым словом unsafe. Слово unsafe не отключает проверки, а просто добавляет пару слабо контролируемых компилятором возможностей. Но основное назначение этой штуки — не оптимизация алгоритмов, а FFI и обращения к железу, которые компилятор проверить не может. Они тоже считаются unsafe. Поскольку слово unsafe в коде встречается редко (под ним будет всего несколько строк), проверить алгоритм вручную становится намного легче. При необходимости слово unsafe можно вообще запретить в модуле или во всем проекте, благо алгоритмы вроде связных списков и все важные системные вызовы уже реализованы в стандартной библиотеке. В большинстве реальных программ слово unsafe не встречается нигде или встречается только в интерфейсе к чужим библиотекам на C/C++.


          Можно не пользоваться git, при этом cargo будет работать примерно как обычный cmake и все. В таком режиме можно использовать svn и что угодно еще. Если использовать git, появляются некоторые дополнительные возможности по работе с зависимостями.

            –11
            Поскольку слово unsafe в коде встречается редко (под ним будет всего несколько строк), проверить алгоритм вручную становится намного легче

            раст — это язык, в котором куча рассчитанных на новичков статей повторяет одну и ту же пропаганду. Кто, блин, проверяет код вручную в проектах больше хелловорлда? Правильно, никто. Не говоря уже про то, что причина возникновения ub вполне может прятаться в "safe"-коде. Это "магическое" unsafe абсолютно бесполезно, и по этой причине отсутствует в других языках

              +12
              unsafe с сырыми указателями есть и в C# например
                +16

                Так в том и дело, что весь код проверять и не надо. Только unsafe блоки. В них обычно пишут больше всевозможных проверок и покрывают их тестами.


                Я уже года 4 пишу на расте и за всё время мне unsafe понадобился всего пару раз. Это были переписывания с C/C++ на раст и такой код был временным клеем. Как только последняя функция была переписана на расте — он удалялся. И в чистом коде на расте никакого unsafe уже не было.


                Ну и важно понимать, что даже unsafe раст намного безопаснее C/C++. У компилятора есть проверки которые он выполняет всегда (safe и unsafe) и проверки которые доступны только в safe. Это всего лишь означает, что компилятор не может сделать это сам и требуется помощь человека (обычно это означает, что нужны тесты для этого куска кода).

                  –9
                  Даже в чистом расте unsafe бывает часто необходим, например, для доступа к глобальным переменным.
                    +13

                    Глобальные переменные в прикладном программировании не нужны.

                      +4
                      В embedded, куда собственно раст тоже метит, очень часто бывают нужны, потому что там нет динамической памяти и стек очень ограничен.
                        +1

                        Тоже не нужны. https://crates.io/crates/cmim

                          0
                          И что это доказывает? Весь крейт — это обертка над UnsafeCell и unsafe кодом. Там даже тестов нет, так что никто не знает работает ли это вообще или нет. Плюс это лишь для работы с данными внутри прерываниях. Я же говорю про глобальные объекты в целом. Всякие буферы для сетевых операций, большие жирные объекты для логики приложения где хранить как не глобально?
                            +5
                            Всякие буферы для сетевых операций, большие жирные объекты для логики приложения где хранить как не глобально?

                            А зачем хранить их глобально?

                          +6

                          Эти unsafe'ы можно завернуть в безопасный интерфейс. См. например: https://docs.rust-embedded.org/book/concurrency/index.html#global-mutable-data

                            –2
                            То, что unsafe можно завернуть в safe обертки ещё не гарантирует memory safety для клиентского кода. Кто знает, может в этих safe обертках творится настоящий ад из утечек и повреждений памяти. Клиентский же код будет всё время находится с чувством ложной безопасности до того момента, когда всё упадёт.

                            Это больше всего напоминает запихивание мусора под ковёр во время уборки.
                              +8

                              В смысле — "кто знает"? Откройте их исходный код да посмотрите!


                              Те самые мифические программисты, которые всегда на Си пишут без ошибок, уж точно должны быть способны один раз написать безопасные обёртки для стандартной библиотеки Rust.

                                0
                                Часто ли вы испектируете все зависимости, которые используете? А зависимости зависимостей? У меня вот на мелких проектах с 2-3 зависимостями тянется около 100 крейтов с репозитория. И что, предлагаете все их просматривать и инспектировать на предмет корректности в unsafe коде? Проще застрелиться.
                                  +4

                                  Лично я — часто. Но в случае с распространёнными библиотеками можно с некоторой вероятностью положиться на сообщество.


                                  А вот часто ли сишники инспектируют свои зависимости?

                                    0
                                    А вот часто ли сишники инспектируют свои зависимости?

                                    Лично я — всегда. В тех областях где применима "сишка", это просто перетекает в обязанность. Я просто не могу применить в Embedded код о котором я ничего не знаю. Например, сколько он жрёт памяти, есть ли там динамические аллокации и т. д.


                                    На плюсах в моей области та же ситуация. Нужно ли мне тянуть Boost ради Event-loop или я напишу его сам для трёх дескрипторов на kqueue/epoll.


                                    На Python кстати вообще почти не тяну левых библиотек, т.к. у него на мой взгляд одна из лучших стандартных библитек, которая покрывает мои запросы на 90%.


                                    Я искренне желаю, чтобы инфраструктура Rust не повторила ошибок Node.js и NPM.

                                      0

                                      Кстати в расте хорошо то что код который требует аллокаций явно об этом говорит видом extern crate alloc;

                                +6

                                Это гарантирует, что если API библиотеки выполняет контракт, то memory safety будет независимо от способа использования этого API.


                                Хотя это не обеспечивает абсолютную безопасность, это дает намного бОльшую безопасность, чем написание в стиле Си, где вообще весь код unsafe. Проверить вручную один раз пять простых строк в safe-обертке намного легче, чем дебажить каждый клиентский проект.

                                  –4
                                  И да, и нет. Да, если ваш случай использования совпадает с тем, о чем думал автор при написании. Но часто бывает так, что всякие скрытые контракты авторы библиотек не документируют (потому что не учли), а документации красуется 100% safe.

                                  В хороших библиотеках на С в свою очередь документируется стратегия владения объектами (потому что иначе никто не сможет это использовать) и это в обязанностях программиста следовать им.
                                    +2

                                    Что такое, в вашем понимании, "скрытый контракт"?

                                      –2
                                      Это контракт, который нигде не задокументирован, но неявно вытекает из реализации метода.
                                        +1

                                        В худшем случае он запаникует на каком-то инварианте или потечет памятью. Не напортачит молча не ту память и не совершит уб

                                      +5
                                      В хороших библиотеках на С в свою очередь документируется стратегия владения объектами (потому что иначе никто не сможет это использовать) и это в обязанностях программиста следовать им.

                                      А в Rust эта задача возложена на компилятор. Не совпали ожидания — код просто не скомпилируется.

                                    0
                                    Не используйте библиотеки и обертки, которые недостаточно протестированы и в которых может твориться настоящий ад из утечек и повреждений памяти. Emdedded — это всего лишь малая часть от всего кода на Rust, и в обычных проектах чувство безопасности у клиентского кода вовсе не будет ложным. При этом, если писать на C++ такие же обычные проекты, избежать ошибок памяти без опыта использования современных фич C++ очень сложно, а избежать UB вообще считай что невозможно.
                                      –3
                                      Не используйте библиотеки и обертки, которые недостаточно протестированы и в которых может твориться настоящий ад из утечек и повреждений памяти
                                      этот совет по сути сводится к использованию только тех библиотек, код которых вы лично перепроверили.
                                      При этом, если писать на C++ такие же обычные проекты, избежать ошибок памяти без опыта использования современных фич C++ очень сложно
                                      без опыта на любом языке тяжело писать.
                                      а избежать UB вообще считай что невозможно.
                                      а вот тут можно вдаваться в очень глубокую демагогию. Дело в том, что стандарт с++ очень явно определяет какое поведение определено стандартом, какое реализацией, а какое не определено совсем. Соответственно, кусок кода, не содержащий UB, обязан быть корректным. Однако спецификация rust куда менее строгая, большая часть описанных в ней гарантий покрывает именно safe код, и формально практически любой код с unsafe является UB.
                            +1
                            Вот смотрите «safe rust» подмножество языка накладывает на код множество инвариантов, благодаря которым часть ошибок невозможна.
                            Надо заметить, что это «очень умное множество инвариантов» (ОЧЕНЬ УМНОЕ МНОЖЕСТВО ИНВАРИАНТОВ). Вынь любой из них — и вся Rust Safity посыпется.

                            Так вот проблема таких unsafe-блоков (как я её вижу) в том, что:
                            1.) unsafe-блок — это «вот в этом коде мы нарушили инварианты. Реальная ошибка может проявиться где угодно далее.
                            2) Пользователю предлагается „на коленке“ проверить и поверить, что его программа, хоть и нарушает Rust-safe инварианты, всё ещё сохраняет safity (просто из-за того, что его программа частный случай) — это весьма хлопотно.
                            2.б) Пользователю предлагается не просто однократно поверить, а как правило поверить на всё дальнейшее время существования программы, что unsafe-блок останется безопасным, как бы не менялась safe-часть его программы.

                            Вообще недоверие к пунктам „2“ и „2.б“ по-моему вполне оправдано.

                              +4
                              проверить, что его программа, хоть и нарушает Rust-safe инварианты, всё ещё сохраняет safity
                              Это слабый вариант. В идеале,
                              1.б) автор unsafe блока должен проверить, что unsafe block будут сохранять safity в контексте любого safe кода, а не только в частном случае конкретной программы.

                              Особенно если этот unsafe блок находится в библиотеке. Если сильный вариант проверки выполнен, пользователь может не волноваться и 2) и 2б) не требуются.
                                +1

                                Ну можно впасть в крайность и разметить весь код как unsafe. И даже в этом случае получится язык более безопасный чем C/C++.


                                Процитирую мануал. В unsafe коде можно дополнительно делать:


                                • разыменовывать указатель
                                • вызывать другой unsafe код
                                • обращаться к глобальным переменным
                                • реализовывать unsafe traits
                                • использовать union-ы

                                Всё! Все остальные инварианты и проверки сохраняются, в том числе и пресловутый borrow checker.

                                  –3

                                  Борровчекер не поможет запретить трансмут &t -> &mut t, а если ансейф глобальный то ничто не мешает. Да, это УБ, но в итоге по безопасности +- те же плюсы

                            0
                            Для списков и вообще для хитрых алгоритмах на указателях, правильность которых доказана на бумаге, в Rust есть указатели в стиле Си (без проверки области видимости).

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

                              +7

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


                              Полностью автоматическое доказательство правильности в любом случае принципиально невозможно из-за проблемы остановки. Rust решает проблему остановки тем, что проверяет автоматически большинство алгоритмов, а не все. Для оставшегося меньшинства программисту на выбор предлагается два варианта: перенести проверку на runtime или провести некоторые действия с неполной проверкой.


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

                                0
                                Проблемы остановки не существует для компьютеров с конечным числом состояний.
                                  0

                                  Эй, почто человека минусуете? Если у компьютера конечное число состояний, то компьютер с достаточно бо́льшей памятью может построить полный граф переходов между состояниями и найти в нём все циклы.

                                    +4

                                    В теории — да, а вот на практике понадобится слишком много памяти. Это во-первых.


                                    А во-вторых, сама идея доказывать правильность работы программы исходя из той посылки, что на компьютере где программа будет работать будет не более X памяти отдаёт чем-то странным. Пройдёт время, появятся компьютеры с большим объёмом памяти — и что тогда? Правильный алгоритм должен иметь ограничение на используемую память снизу, а не сверху.

                                      +10

                                      У компьютера с 64кбайт памяти 2^524288 состояний, машина Тьюринга с 6-ю состояниями может проработать 10^36536 шагов перед тем как остановится.


                                      Не в нашей вселенной такое перебирать.

                                        0
                                        Изначальный посыл был «Полностью автоматическое доказательство правильности в любом случае принципиально невозможно»
                                        Для конечной машины всегда возможно.
                                          0

                                          "Принципиально невозможно в любой вселенной, имеющей ограниченные вычислительные ресурсы". Так пойдёт?

                                            +1
                                            В предложенном вами примере достаточно всего 10^36536 шагов для решения задачи в общем виде для указанного компьютера.
                                              0

                                              Так в какой вселенной будем анализировать? В нашей? Не выйдет. В той, в которой выйдет? Там можно взять машину Тьюринга с 7-ю состояниями. И тоже не выйдет.

                                                +1
                                                Вы можете уточнить исходное определение (например, уточняя понятие «вселенная» и дополняя понятие «ограниченности» временным ограничением), назовем это «расширенным утверждением», и будете скорее всего правы в рамках ваших расширенных допущений. Однако это не означает неправоты моего ответа на изначальное более общее утверждение другого участника Хабра.
                                          0

                                          Верно, но немного лукаво. Только часть доступной памяти участвует в реализации алгоритма и конечность многих конструкций доказывается формально. Это позволяет значительно снизить вариативность, на чем мы люди и держимся :)

                                            +1

                                            Мы, люди, держимся на том, что не пытаемся решать проблему остановки (точнее, обойти теорему Райса). Мы не берём произвольный алгоритм, и потом пытаемся доказать, что он решает нужную задачу. Мы конструируем алгоритм под задачу. Правда баги и CVE показывают, что алгоритмы сконструированные таким способом обычно решают не совсем ту задачу.


                                            Исходного посыла это не меняет. Невозможно (ни практически, ни теоретически) решить проблему остановки. Тут помогут только супер-Тьюринговые компьютеры, которых не видно даже на горизонте.

                                      +1
                                      > Полностью автоматическое доказательство правильности в любом случае принципиально невозможно из-за проблемы остановки.

                                      А в каком контексте проблема остановки связана с операциями на списках, которые вы упоминаете выше? Можно подробнее в деталях?

                                      По существу, проблема остановки решаема для linear-bounded automaton. Ну и формальная верификация алгоритмов для списков (и вообще для арифметики на указателях) при помощи компилятора уже существует, просто Rust так не умеет:
                                      * ats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/HTML/HTMLTOC/c3321.html
                                      * ats-lang.github.io/DOCUMENT/INT2PROGINATS/HTML/x3828.html
                                        +3

                                        Проблема остановки лишь приводит к необходимости иметь в языке "unsafe" для самого общего случая. Частный случай со списками возник по другой причине, а "unsafe" для него использовали потому, что он все равно уже был в языке.


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


                                        Код указателей и прочих unsafe-действий тоже верифицируется, но менее строго. Например, в stable rust до последнего времени не было способа сказать, что приходящий из чужого модуля указатель никогда не бывает нулевым (теперь есть, NonNull называется). Пока нет в общем случае способа сказать, что указатель на объект из коллекции не затрагивает другие объекты (единственное, что можно сказать — что это указатель на объект, принадлежащий другому объекту). В подобных случаях мы пока что просто говорим компилятору "поверь нам на слово, что так делать можно". Либо добавляем проверку на рантайме в надежде на то, что оптимизатор обнаружит инвариант и выкинет эту проверку.


                                        Пример со списками: если написать модуль для списков, то есть способ сказать компилятору, что функция push() как-то изменяет содержимое списка, но нельзя сказать, что она не инвалидирует указатели на уже имеющиеся элементы. Хотя компилятор в принципе способен это вывести сам, он не имеет права, так как в сигнатуре функции мы этого не сказали, и, возможно, в будущем планируем поведение функции push() изменить.


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

                                          –2
                                          > Частный случай со списками возник по другой причине, а «unsafe» для него использовали потому, что он все равно уже был в языке.

                                          ок, значит имплементации разных списков и unsafe в них — не про HP, и теоретически нет непреодолимых препятствий проверять их безопасность компилятором — есть проблема эргономики, о которой вы говорите ниже.

                                          Но тогда у меня есть философский вопрос: если Rust позиционирует себя относительно С/С++ как язык, который позволяет предотвращать проблемы безопасности по памяти и продвигает себя в аудитории, для которой эти проблемы должны быть важны и насущны, то почему в этом позиционировании присутствует вопрос эргономики, который изначально субъективен и не направлен на обобщенное решение проблем с памятью?

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

                                          То есть, если я тот инженер, перед которым стоит задача решить проблемы безопасности софта по памяти, мне не очень понятен аспект эргономики, ради которой приходится жертвовать безопасностью в некоторых случаях, особенно если эти случаи распространены в низкоуровневом коде ядер ОС и драйверов. Для меня как для инженера более логично выбрать инструмент, который решает эту проблему обобщенно, без оглядки на эргономику. А уже когда эта основная задача покрыта, можно подумать об эргономике.
                                            +4

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

                                            +2

                                            Мне кажется тут разумнее упомянуть теорему Райса, а не проблему остановки.


                                            Хотя вывод примерно тот же

                                            0
                                            К тому же вполне возможна формальная верификация программ, написанных на C, например микроядро seL4 тыц
                                            Ну и фреймворки типа Frama-C помогают писать спецификации прямо в коде.
                                            0

                                            Немного оффтоп. Вы 7 лет пишете коммерческий софт? Если да, то расскажите немного подробнее, пожалуйста.

                                            +1

                                            Потому что Rust это практичный компромисс между полным отсутствием проверок (С/С++) и слишком сложными и медленными системами доказательств.


                                            И, как показывает опыт, компромисс вполне удачный. Этого самого unsafe кода исчезающе мало по сравнению с остальным кодом.

                                            0
                                            Связный список технически можно написать на 100% safe Rust на умных указателях
                                            но будут дополнительные расходы на подсчет ссылок.
                                            В большинстве реальных программ слово unsafe не встречается нигде или встречается только в интерфейсе к чужим библиотекам на C/C++.
                                            на этот счет есть какая-то статистика? А то утверждение кажется чересчур амбициозным
                                              –1

                                              У меня нет статистики. Но мне кажется позиционирование Rust как убийцы C/C++ не совсем верно. Он скорее приходит в область где правили Go и Java. Там где рулили языки с GC. А теперь появилась альтернатива с высокой производительностью и богатыми возможностями.


                                              А вот в каком-то Embedded usafe кода просто не избежать.

                                                +4
                                                на этот счет есть какая-то статистика? А то утверждение кажется чересчур амбициозным

                                                Есть. Оценка там довольно грубая, но по ней выходит, что около 70% крейтов не содержат unsafe-код вообще и что в целом 95% кода, размещенного на crates.io, является safe.

                                              +3

                                              Есть отличная статья по теме списков

                                                +1
                                                Двусвязный список уже в стандартной библиотеке Rust: std::collections::LinkedList.
                                                Альтернативная реализация c unsafe-кодом в репозитарии RustAlgorithms: ссылка на linked_list.rs
                                                И реализация без unsafe-кода: leviathan88/safe_lists_rust
                                                  0

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


                                                  пример
                                                  use slab::Slab;
                                                  type NodeID = usize;
                                                  
                                                  pub struct LinkedList<T> {
                                                      head: Option<NodeID>,
                                                      tail: Option<NodeID>,
                                                      elements: Slab<Node<T>>,
                                                  }
                                                  
                                                  struct Node<T> {
                                                      prev: Option<NodeID>,
                                                      next: Option<NodeID>,
                                                      data: T,
                                                  }

                                                  Для простой структуры, вроде двусвязного списка, данных подход может показаться переусложнённым. Но она уже реализована и оттестирована в стандартной библиотеке. А в качестве "простой" альтернативы, можно использовать счетчики ссылок (Rc/Weak), или окунутся в C-like код с сырыми указателями. Кстати, в std двусвязный список реализован именно на них.

                                                  +4
                                                  А как обстоят дела с GUI?
                                                    +4

                                                    https://www.areweguiyet.com/ — вот тут собирают информацию о состоянии GUI в Rust.


                                                    Из личных наблюдений — есть очень приличный gtk-rs (привязка к gtk3), куча обвязок вокруг WebView, и написанные с нуля библиотеки со скупыми наборами виджетов.

                                                      +2
                                                      Да это видел, просто интересен опыт именно тех кто пробывал сам
                                                        +4

                                                        Я пробовал байндинги к gtk3, qt, cocoa, winapi. Самым беспроблемным с точки зрения соответствия оригинальной документации являлся, внезапно, winapi — можно код на си напрямую переписывать в Rust (естесственно, завернув в unsafe). Следом идет cocoa, который мог бы быть первым, но для замыканий и другого асинхронного кода там намутили, разумеется, забыв задокументировать. Qt слегка наркоманский в плане API, но если понять принцип, становится несложно, но многословно. Gtk прекрасно используется, пока вы используете стандартные контролы, но стоит отойти в кастомизацию или расширение стандартного функционала, начинаются приключения — документации нет, иногда вырезана поддержка в коде (кастомные сигналы).

                                                        0

                                                        Ещё Flutter как вариант. Хотя думаю смысл раста в нём только если нужно писать куски кода для доступа к нативному API системы, вместо C/C++.

                                                          0
                                                          www.areweguiyet.com — вот тут собирают информацию о состоянии GUI в Rust.


                                                          Думаю вот эта ссылка будет куда полезней.
                                                          +1

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


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


                                                          Для immediate mode есть биндинги к imgui, но т.к. стояла задача кроссплатформы без внешних либ вообще, то не стал их использовать.

                                                            +3
                                                            Про состояние GUI мне понравилась вот эта статья: dev.to/davidedelpapa/rust-gui-introduction-a-k-a-the-state-of-rust-gui-libraries-as-of-january-2021-40gl

                                                            Там автор потрудился попробовать несколько гуишных крейтов и поделился своими впечатлениями.
                                                            +1
                                                            Насколько будет быстрым вызов из внешних dll, написанных на C/C++? Быстрее, чем [DllImport] в C#?
                                                              +1

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

                                                                +6

                                                                Вопрос не совсем корректен, тк не относится конкретно к расту. Rust генерирует бинарники в формате целевой платформы, например ELF на линуксе, и этот бинарник обычным образом вызывает код из динамической библиотеки, через Posix С ABI. То же произойдёт если бинарник написан на си или на плюсах. ЕМНИП первый вызов будет более медленный (оверхед на поиск функции в таблице PLT), остальные быстрее.


                                                                Так что вопрос здесь "скорость вызова DLL в C# и в компилируемых языках". Не знаю правильный ответ на этот вопрос, интуитивно кажется что компилируемые языки делают вызов из DLL быстрее. Но вот обратный пример с luajit. Там есть ссылка на проект на гитхабе с бенчмарками различных языков при вызове .so кода, шарп там медленнее компилируемых языков. Короче всё зависит от механизма вызова.

                                                                  +2

                                                                  Rust не добавляет дополнительного оверхеда к таким вызовам. Скорость будет неотличима от C/C++ на компиляторе с тем же бэкэндом и аналогичном линковщике.

                                                                  +2
                                                                  Интересна история вопроса, почему отказались от green threads в пользу системных потоков?
                                                                    +10

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

                                                                      +6
                                                                      Вы можете посмотреть RFC где подробно описаны причины.
                                                                      Если вкратце, разработчики Rust решили что это язык для максимально эффективного системного программирования и должен иметь минимальный runtime.
                                                                      Так же думаю, что зеленые треды мешают эффективному FFI с C. Например в Go любой вызов C функции это относительно дорогая операция.
                                                                        0

                                                                        Правильнее будет спросить, что сейчас сделалось с green threads. В Rust появилась библиотечная реализация фьючерсов, причем не требующая переключать стэки, с нулевым оверхедом, а потом на ее основе сделали async/await. Все это делает зеленые потоки в большинстве задач ненужными. Также появилась библиотечная реализация классических зеленых потоков. Все это позволило обойтись без встроенной в язык поддержки.


                                                                        Поддержку системных потоков язык обязан иметь потому, что компилятор должен уметь проверять корректность передачи данных между потоками. Хотя сама реализация системных потоков тоже в библиотеке, язык знает, что такое "исполнение в другом потоке" и "thread-local".

                                                                        +6
                                                                        Кложура. Этим словом можно детишек пугать: вот придёт кложура, как вручит словарь русского языка!
                                                                          0
                                                                          Поправил :)
                                                                            0

                                                                            Не ешьте функцию вместе с кложурой!

                                                                            +12

                                                                            Как-то приелись мотивашки по расту и статьи со введением в Rust, их уже наштамповали мильён, а вот материалов более высокого уровня наоборот не хватает, из стандартных только rust reference и nomicon.

                                                                            –22
                                                                            MSRC Security Research 2019 года (Microsoft) показал, что 70% Common Vulnerabilities and Exposures (CVEs) в их продуктах были связаны с проблемами безопасности памяти в С и С++ (думаю весьма известный график):

                                                                            В C и в C++ нет никаких проблем с безопасностью памяти, поскольку malloc() и free() — это всего лишь обертки системных вызовов в ядро. Каких-то более «безопасных» системных вызовов управления кучей нет. При этом никто не мешает на их основе создавать субаллокаторы с проверками и прочим, тем более, что С++ предоставвляет такую возможность для всех своих контейнерных классов.
                                                                            Проблема «безопасности памяти» не в языках, а в программистах. Из всех перечисленных выше «проблем» за всю свою долгую жизнь в C и С++ и даже в ассемблере не помню ни одной, с которой пришлось бы столкнуться. Налететь на них можно только если сильно спешить и писать код напрямую с головы, не предваряя кодирование проработкой алгоритмов, протоколов обмена объектами и прочим, что должно прорабатываться до тогшо, как начнет создаваться код, котороый увидит свет.

                                                                              +11

                                                                              Но как и в любой другой работе, зачем её делать вручную, если можно делать не вручную?


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

                                                                                –2
                                                                                Но как и в любой другой работе, зачем её делать вручную, если можно делать не вручную?

                                                                                Вот и я так думаю. Зачем вручную воевать с borrow checker, лайфтаймами, элементарные вещи делать через стандартную библиотеку.


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

                                                                                  +4
                                                                                  Зачем вручную воевать с borrow checker, лайфтаймами, элементарные вещи делать через стандартную библиотеку.

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

                                                                                    –2
                                                                                    А что если мне нужна безопасная семантика владения, которая не поддерживается borrow checker'ом? В других языках я могу определить свою семантику владения, и даже формально доказать ее безопасность, а в Rust мне придется воевать с компилятором и расставлять unsafe по коду.
                                                                                      0

                                                                                      Что такое "своя семантика владения"? По вашей ссылке что-то странное написано.

                                                                                        0
                                                                                        Своя семантика владения это например когда я могу иметь безопасный ring buffer (у него же есть семантика владения объектами внутри структуры) без unsafe в имплементации. У Rust нет механизма описания кастомной внутренней семантики владения, которая бы точно описывала почему та или иная структура и операции над ней безопасны по своей природе, и поэтому всё что не укладывается в правила выбранные авторами компилятора считается небезопасным.

                                                                                        > По вашей ссылке что-то странное написано.

                                                                                        а вот так лучше?
                                                                                          +1

                                                                                          Значит для ваших задач удобнее другая техника безопасности. Пользуйтесь ей, никто не запрещает.

                                                                                        0
                                                                                        Те кто минусует, я вас приглашаю к предметному диалогу. Не нужно быть фанатичным последователем культа Cargo, если вы сами в статьях и комментариях инициируете обсуждение вопросов безопасности по памяти в софте.
                                                                                          +3
                                                                                          «Своя семантика владения», «20 лет пишу, ни разу в ногу не стрелял» — это всё про одно и то же: про честное слово конкретного программиста и то, насколько мы ему доверяем — и это для всего кода. Раст же гарантирует отсутствие UB «из коробки» во всём safe коде, а unsafe блоки, где программист обещает, что «всё чисто», проще проанализировать, чем весь код, как в первом случае.
                                                                                            0

                                                                                            Да тут с обоих сторон, похоже, фанатиков хватает, мне тоже кто-то плюнуть в карму успел, при том что ни единого ответа по существу ни от кого, кроме вас, не было ¯\_(ツ)_/¯

                                                                                            +2
                                                                                            Конечно, есть языки с более продвинутой системой типов чем у Раста, но у них свои проблемы. Идея Раста в том что бы найти удачный компромисс между универсальностью асма и C, безопасностью и эргономикой, при этом не отходить от принципа «What you don’t use, you don’t pay for». В эргономику я также включаю расходы на поддержку и тестирование кода.
                                                                                            Возможен ли язык, который лучше раста по всем направлениям? Конечно, возможен, но я о нем пока не слышал. Более того, по моему мнению, для многих задач Rust является лучшим языком в совокупности на данный момент, лучшим выбором в целом, так сказать. И число таких задач продолжает увеличиваться. Haskell и ко тоже круты, но Rust выходит сильно практичнее.
                                                                                          +5

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


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


                                                                                          С синтаксисом да, беды есть, т.к. авторы и сами заявляли, что затачивали его под более простой парсинг, чем под лёгкую читабельность. Но после пары проектов вызывает дискомфорта куда меньше, чем те же плюсы (при условии, что проекты не уровня хелловролд, а именно полноценных с дженериками и прочими темплейтами) — опять же, сугубо субъективно.

                                                                                            –1
                                                                                            Ну так и пишите на ассемблере сразу, зачем заморачиваться с чем-то вообще, если можно всё сделать интуитивно и просто?

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


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

                                                                                            Я никогда в Embedded и в разработке модулей ядра ОС не теряю аллокаций. Потому что в первом случае их вообще нет, либо как у Rust unsafe — 0,0001%. Во втором их тоже две-три штуки. А дальше, дальше не нужно на Си писать микросервисы.


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

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

                                                                                              +4

                                                                                              У каждой сущности есть владелец — вся концепция Rust.


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

                                                                                                +3
                                                                                                Нет, ассамблер не интуитивен.

                                                                                                Опять же, вкусовщина, по мне Z80 асм проще в изучении, чем средний бухгалтерский калькулятор. А вот в х86 таки да, недоперемудрили, если ещё и лезть в MMX/SSE/2/3/4 :-) Даже на Altivec как-то попроще казалось. Но да ладно, это уже всё флуд.


                                                                                                Я никогда в Embedded и в разработке модулей ядра ОС не теряю аллокаций.

                                                                                                Ну вот, это просто ваш частный случай, где оно и не нужно.


                                                                                                не нужно на Си писать микросервисы.

                                                                                                А почему бы и не писать? Но вот на чистом Си оно больно и трешово, а на Расте элементарно, при том что производительность примерно та же.


                                                                                                У меня лично Rust занял весьма широкую нишу, если можно так выразиться, в геймдеве, а именно написании альтернативных серверов к играм. 120 активных юзеров, поделка на ноде жрала под пару гиг оперативки, на расте хватает пары сотен метров. Либо эмулятор лицензионного ключа, чтобы не пилить оригинал лишним использованием — тут уже всё чисто даже на стандартной библиотеке делается, т.к. удобные сокеты есть, строки есть. Всякие лоадеры и патчеры тоже — можно, конечно, писать на том же сишарпе, но это будут вагоны врапперов поверх WinAPI и прочего треша, можно писать на Си — но банально неудобно.


                                                                                                Плюс элементарнейшая кроссплатформенность. На си приходилось думать, как и куда что обернуть для этого, на расте просто делаешь cargo build, разве что докинув тулчейн для кросс-компиляции. В итоге пишешь сервер на винде на машине с игрой, а деплоишь на линуксовую в один тык. Или пишешь на современной винде, а потом деплоишь на эмбеддед винду XP, правда уже с нюансами — там стандартная библиотека неполная, нельзя мьютексы и ещё что-то использовать. Но сам факт, что по простоте сравнимо с той же джавой, для меня был решающим.


                                                                                                Изучением системы типов тоже не занимался, просто начал писать код сразу, и как-то оно само дальше в голову залетало. Оно уже потом заинтересовало, когда стало ясно, насколько это удобно, когда код либо работает, либо даже не собирается :-)

                                                                                          +6

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

                                                                                            +8
                                                                                            В C и в C++ нет никаких проблем с безопасностью памяти

                                                                                            Да-да, а эти самые CVE враги выдумали?


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

                                                                                            Вот только такие проверки придётся делать в рантайме, т.е. на них будет тратиться время.


                                                                                            Проблема «безопасности памяти» не в языках, а в программистах.

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

                                                                                            +1
                                                                                            Интересно, для чего huawei планирует использовать rust. Просто, абсолютное большинство вакансий — это какой-нибудь блокчейн, что не для всех интересно.
                                                                                              0
                                                                                              Использовать Rust для блокчейна тоже можно.
                                                                                                +4
                                                                                                разве я говорил, что нельзя? Просто, это не всем интересно и регулярно встречаю обсуждения «а что есть, кроме блокчейна».
                                                                                                Huawei делает много интересного, возможно, появятся вакансии, совмещающие интересный язык с интересной сферой деятельности.
                                                                                                  –7
                                                                                                  это не всем интересно
                                                                                                  Не интересен блокчейн — не подавайте резюме на блокчейн-вакансию, вас же не заставляют. А если хочется работать именно в Huawei, но не с блокчейном — ну простите, они не будут подстраиваться под конкретно ваши желания.
                                                                                                    +8
                                                                                                    я не понимаю ваш комментарий.
                                                                                                    Я никого не заставляю подстраиваться. Просто спрашиваю.
                                                                                                    Если Huawei планирует тоже использовать rust только для блокчейна — ок, все понятно.
                                                                                                    Но спросить то можно?
                                                                                                      –4
                                                                                                      Хорошо, вернёмся к началу:
                                                                                                      Интересно, для чего huawei планирует использовать rust
                                                                                                      Для чего угодно.
                                                                                                      Просто, абсолютное большинство вакансий — это какой-нибудь блокчейн, что не для всех интересно.
                                                                                                      Ну и ладно, не интересно так не интересно.
                                                                                                      Почему вы вдруг решили, что Rust у них должен пойти только в новые проекты и от новых людей? У них и своя мобильная ОС есть, и оборудование они делают, и мало ли что ещё.
                                                                                                        +7
                                                                                                        Вы это говорите от имени huawei, или это ваше личное мнение.
                                                                                                        Если ваше мнение — то и так понятно, что на расте можно писать (почти?) все и что он может применяться и на старых и на новых проектах.
                                                                                                        Просто, если такой крупный вендор будет использовать раст для разработки мобильной ОС, для оборудования — что угодно за пределами блокчейна — это большая новость для раст сообщества.
                                                                                                        Понятно, что даже если блокчейн — все равно большая новость, да и блокчейн многим нравится, но потребность в не-блокчейн проектах на расте довольно большая.

                                                                                                        Поэтому, хотелось бы получить ответ от автора.
                                                                                                          0
                                                                                                          Так как это все внутренние планы и проекты, более детальный ответ предоставить не могу.
                                                                                                          Вероятно это не тот ответ, который вы ожидали от меня, но в этом вопросе я не могу вам помочь.
                                                                                                            0
                                                                                                            Все равно спасибо.
                                                                                                    0
                                                                                                    разве я говорил, что нельзя? Просто, это не всем интересно и регулярно встречаю обсуждения «а что есть, кроме блокчейна».

                                                                                                    Есть HFT :) Бувально на следующей неделе планирую пособеситься в очередную контору

                                                                                                0
                                                                                                Почему вы должны попробовать Rust

                                                                                                Где описание как скачать и установить и какие системные требования?
                                                                                                  0
                                                                                                  Вообще-то рекомендуется использовать rustup для установки…
                                                                                                    +1

                                                                                                    А зачем это описание нужно? Неужели найти эту информацию самостоятельно так сложно?

                                                                                                      0
                                                                                                      И какие системные требования у rust-а?
                                                                                                        0
                                                                                                        Простите, но ваш вопрос такой же бессмысленный, как «Какие системные требования у Python». Не бывает у языка системных требований, они бывают у инструментов сборки, отладчиков, рантайма, но не языка. Потому что сам по себе язык — не более чем способ записи алгоритма по определённым правилам.
                                                                                                        Да, я зануда.
                                                                                                          0
                                                                                                          Раст в том виде что он есть, имеет системные требования или уже много альтернатив есть?
                                                                                                          Тот же python: «Python 3.8.8 cannot be used on Windows XP or earlier» чем не требование.

                                                                                                          Сколько надо выделить виртуальной машине ресурсов что бы оно завелось и компилировало.
                                                                                                          Тот-же си очень скромные требования имеет и есть в огромном количестве исполнений.
                                                                                                            +2
                                                                                                            или уже много альтернатив есть
                                                                                                            Так а какой вам конкретно инструмент потребовался? Только сам rustc? Или вместе с cargo? Требуют ли ваши крейты компиляции каких-то внешних библиотек (обычно это при сборке для Windows, но тем не менее)? Под какую платформу вы планируете собирать (компиляция в WASM иногда съедает гораздо больше памяти, чем в нативный код)? Разрабатывать хотите на той же машине, или вам только для сборки интересно? Если разрабатывать — будете ли вы Language server использовать? Если да — RLS или Rust Analyzer? Набор инструментов, может, и один, но переменных в уравнении «хватит — не хватит» предостаточно.
                                                                                                            Python 3.8.8 cannot be used on Windows XP or earlier

                                                                                                            Зато есть MicroPython, который аж в микроконтроллерах работает.
                                                                                                    +1
                                                                                                    Почему вы должны попробовать Rust

                                                                                                    1. Память
                                                                                                    2. Многопоточность
                                                                                                    3. Тестирование
                                                                                                    4. И документация


                                                                                                    И это всё?
                                                                                                    Знаете, с такой рекламой я лично языком не заинтересуюсь. Другого жду от языка.
                                                                                                      +2

                                                                                                      Лично я заинтересовался Rust'ом после того, как он начал на хабре регулярно всплывать в комментариях к ФП-шным постам. Про раст услышал году так в 2015 как "про тот сложный язык язык с владением, про который на хабре пишут статьи о том, как строку в функцию передать". А заинтересовался после всех этих трейтов, недо-монад Option и прочих типов-сумм.

                                                                                                        0
                                                                                                        Другого жду от языка.

                                                                                                        Например?


                                                                                                        Но вообще да, все такие статьи страдают тем, что не очень убедительно повторяют одни и те же тезисы. С другой стороны, даже такие "мелочи" как тестирование или документация, когда их распробуешь, начинают цениться намного больше. Есть достаточно инструментов для документирования кода не привязанных к языку, но когда есть один (и главное удобный!) способ причём документация автоматически проверяется при тестировании (опять же — без дополнительных приседаний!), то это качественно другой уровень. Мне кажется, что именно поэтому даже не у самых популярных растовых библиотек есть неплохая документация. С фрейворками для тестирования похожая история.


                                                                                                        Лично для меня "килер-фичи" раста это" бороу чекер, явный ансейф и как раз "инфраструктура". Ну и то, что это "современный язык" во всеми прилагающимися штуками вроде паттерн матчинга.

                                                                                                        –5

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

                                                                                                          +4
                                                                                                          Раст минимизирует трудозатраты на отладку, строго запрещая вам делать то, что в других языках делать просто нежелательно. За счет этой строгости вы убираете огромный класс багов в принципе.
                                                                                                          Согласен, что трудозатраты на обучение больше чем на другие известные мне языки, но не трудозатраты на написание кода! Обучение действительно довольно сложное, но если понять основные принципы (а они не сложные и их довольно немного!) и научиться их применять в коде (тут уже будут проблемы), то именно процесс решения конкретной задачи идет намного более гладко по сравнению с.
                                                                                                          Я, например, чувствую себя с Rust намного более эффективным чем с С++, и возвращаться не желаю.
                                                                                                            +1

                                                                                                            Но если сравнивать с ГЦ языками то раст все ещё заставляет думать там где не хотелось бы. Все эти пины и кросс-реф ссылки между объектами, ...

                                                                                                          +11
                                                                                                          Вот чем лично мне зашел раст, так это:
                                                                                                          1. Комьюнити. Оно тут классное. Всегда помогут, подскажут, библиотеки высокого качества. Простота. Тот же cargo, serde, actix-web — все это учится за полдня и запас по возможностям отличный.
                                                                                                          2. Типизация, дженерики, подобие ООП. Дизайн языка классный, никакого наследования, но есть подобие интерфейсов, можно реализовывать трейты для уже существующих структур.
                                                                                                          3. Функциональное программирование, асинхронность. Причем стандартная библиотека сделана как будто для людей. Каждый раз думаю по привычке после Java, Scala, JS, что вот придется щас утилитный метод писать, ан нет, он уже готовый есть в расте. А мутабельные ссылки? Это же просто красотища. Любую структуру можно сделать имутабельной.
                                                                                                          4. А еще раст следит за многопточностью. И если я вдруг где то что-то забыл синхронизировать, компилятор подскажет.
                                                                                                          5. Обработка ошибок. Никаких больше этих непойманых рантам эксепшенов. Никаких споров, мол что лучше вернуть результат или исключение бросить. Все очень явно.
                                                                                                          6. И при этом всем он чертовски быстрый! В нем нет ограничений в виде виртуальной машины или рантайма, так что производительность ограничена только вашими навыками и временем.

                                                                                                          И вот тут я хотел написать «назовите хоть одну причину, почему это не лучший язык в мире?». Но вот только не пользуюсь я им ровно по одной причине. Ты вроде такой на нем пишешь, и даже не замечаешь что это какой то низкоуровневый язык. А потом выскакивает ошибка типа «already borrowed» и все. Там можно неделю убить. Если какая то оптимизация, и хочется вот тут clone убрать, привет миллион lifetime параметров. И при этом в продакшн не потянешь. Потому что язык таки не простой, где программистов то искать на него? Но это все решается. Ошибки — путем набора опыта, программисты — путем роста популярности.

                                                                                                          Вот такой вот парадокс. То что везде пишут как супер крутую фишку раста стало причиной почему я не могу его использовать.

                                                                                                          Но это я его использовал как высокоуровневый язык, вместо той же Java. Если бы передо мной стоял выбор С++ или Rust, то тут все очевидно (хотя честно говоря, если бы передо мной стоял выбор с++ или <вообще любой другой язык, что угодно, только не с++, пожалуйста>, то я бы тоже вряд ли с++ выбрал бы)
                                                                                                            +2
                                                                                                            А потом выскакивает ошибка типа «already borrowed» и все. Там можно неделю убить.

                                                                                                            Уточнение: убить кучу времени можно не на поиск самой ошибки, а на поиск способа её обхода. И да, неделя — всё равно много как-то.

                                                                                                              +3
                                                                                                              Не на поиск способа обхода, а причину почему она случилась, то самое место которое надо изменить чтобы ошибка пропала ) За год (до этого 10 лет С++) программирования на расте я буквально вчера первый раз поймал то, о чем говорит автор.

                                                                                                              Мне надо смоделировать участок цепи и распространение энергии от источника к потребителям, все сделано так, что есть источники в которые как
                                                                                                              Rc<RefCell<dyn IConsumer>>
                                                                                                              вставляются потребители, источники потом сами дергают методы у IConsumer которые в свою очередь тоже имеют
                                                                                                              Rc<RefCell<dyn IConsumer>>
                                                                                                              (или их vector) что делает дерево.

                                                                                                              Среди потребителей есть контакторы (свичи) которые могут выбирать активный источник, и вот этом дереве я получил «already borrowed» я не смог у себя в голове развернуть все это дело и понять где ошибка, кроме как спустя некоторое время догадался, что какие-то контакторы в дефолте стоят в не верных положениях. Итого: замечательно то, что благодаря этой ошибки можно понять, что цепь имеет не верные соединения, но очень тяжело понять где именно, я себя реально первый раз в расте ощутит беспомощным.

                                                                                                              ПС пока писал этот пост я кажется понял как конкретно в моем частном случае искать где проблема, не буду грузить лишним текстом, лишь скажу, что в общем ситуация не сильно улучшилась, но сузилось количество мест для проверки и поиска.

                                                                                                              Но даже не смотря на все это, я на с++ больше писать не хочу, и не буду, только в legacy.

                                                                                                              А неделя я думаю просто утрирование.
                                                                                                                0

                                                                                                                Это самое место не надо искать, его сообщает компилятор.


                                                                                                                Rc<RefCell<dyn IConsumer>>

                                                                                                                А, ну да, RefCell. RefCell — это такая штука, которая переносит проверки в рантайм. По возможности лучше её не использовать.

                                                                                                                  0
                                                                                                                  Именно, что RefCell, к сожалению не везде я пока могу придумать как его не использовать, особенно после большого опыта в C++, в данном случае если я проектирую программу по другому у меня случается ад в другом месте.
                                                                                                                  Там вон где-то выше по сообщениям напомнили про идею индексов и хранению объектов в другом месте и получать доступ по индексам, буду на днях думать можно ли перепроектировать все на такой подход.

                                                                                                                  В целом после перехода с С++ на раст, очень большая проблема в том чтобы наработать паттерны для решения задач именно на расте, если паттерны которые были наработаны на с++ плюс минус можно использовать в других языках, то в раст надо искать свой подход с ноля :( и зачастую искать самостоятельно путем проб и ошибок.
                                                                                                                    0

                                                                                                                    Индексы — глупость. Лучше уж сделайте у своих потребителей внутреннюю изменяемость, то есть объявите их поля как Cell. Тогда внешний RefCell можно будет убрать.

                                                                                                                      0
                                                                                                                      Я правильно понимаю, что в случае массива мне придется писать что-то типа:
                                                                                                                      struct AConsumer {
                                                                                                                          consumers: Cell<Vec<Rc<dyn IConsumer>>>
                                                                                                                      }
                                                                                                                      
                                                                                                                      impl AConsumer {
                                                                                                                          fn process(&self) {
                                                                                                                              let borrow = self.consumers.take();
                                                                                                                              for v in &borrow {
                                                                                                                                  ...
                                                                                                                              }
                                                                                                                              self.consumers.set(borrow)
                                                                                                                          }
                                                                                                                      }


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

                                                                                                                      Если вдруг кто не понял почему, то при повторном попадание в эту функцию когда она еще не завершена при первом вызове, приведет к тому что Cell::take() вернет пустой массив (т.к оригинальный массив забрал первый вызов), и ничего не произойдёт, тогда как с RefCell второе попадание отловится рантаймом и выпадет паника (ну или нет если вы будете обрабатывать это самостоятельно с try_borrow()).

                                                                                                                      В любом случае спасибо за напоминание, что cуществует еще и Cell.
                                                                                                                        0

                                                                                                                        Не знаю у кого индексы — глупость, арены — типовое решение проблемы раста с расшаренным мутабельным доступом.

                                                                                                              0

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

                                                                                                                +3
                                                                                                                Преимущество над C — безопасность памяти и потоков, что и является основной фичей языка; над Python и JS — многократно большая производительность. Хотя не совсем корректно сравнивать Rust с Python и JS — разные уровни абстракции.
                                                                                                                  +1
                                                                                                                  Хотя не совсем корректно сравнивать Rust с Python и JS — разные уровни абстракции.

                                                                                                                  Согласен, Python и Javascript по выразительности далеко до Rust.

                                                                                                                +2
                                                                                                                К минусам Rust следует отнести достаточно жесткую привязку к одной системе сборки, к одному тулчейну и к одному способу задания зависимостей. GCC front-end пока не достиг высокого уровня, при этом есть проблемы со стабильностью спецификации, что важно для авионики и пр. mission-critical.

                                                                                                                Та же, например, Ada без освобождения памяти (а так обычно обстоят дела в авионике) гарантирует memory safety и thread safety (с использованием protected), и при этом обладает стабильной спецификацией. MISRA-C позволяет уменьшить число неявных ошибок программистов C и т.д. С точки зрения разработчиков и заказчиков таких систем, плюсы от перехода на rust не столь очевидны.
                                                                                                                  +7
                                                                                                                  Я конечно понимаю каждой задаче свой инструмент, но очень часто в жизни, что для одних минус для других плюс. Для меня это наоборот плюс, я настолько устал от С++сного зоопарка, вы себе представить не можете, все эти, cmake, conan, scons, make… и каждый из них полноценная система на другом языке. Проблемы когда vs собирает твой проект нормально, а потом clang на Linux не собирает и т.д…

                                                                                                                  Мой личный опыт показывает что большая вариативность — это скорее минус чем плюс, под вариативностью я понимаю «17 способов инициализировать переменную в C++» В с++ такое везде, начина от компиляторов и систем сборок заканчивая самим языком, везде есть из чего выбрать, а на деле весь этот зоопарк вносить только хаус и проблемы. То что планировалось как гибкость на любой случай жизни превращает многое в ад. Меня до сих пор бросает в дрож когда я думаю о том, что мне надо пойти и создать проект для новой библиотеки на с++, а если мне еще и зависимости внешние нужны, нет, для меня лучше пусть будет одна система с чем то вроде «cargo new my_lib --lib».
                                                                                                                  Опять же я понимаю, что в других сферах этого может быть не достаточно, но прежде чем добавлять вариацию по моему мнению надо очень хорошо подумать.
                                                                                                                  0

                                                                                                                  Язык огонь и имеет замечательные перспективы. Конечно, в ближайшем будущем си/плюсы он не убьет, но познакомиться с ним однозначно стоит. Жаль, руки не доходят(

                                                                                                                    0
                                                                                                                    Хотелось бы, что бы язык активнее продвигался в направление встраиваемой электроники. И в целом порог вхождения в это направление уменьшался.
                                                                                                                      0
                                                                                                                      есть ли возможность писать кроссплатформенные либы под android/ios/windows/macos/linux?
                                                                                                                      сейчас такого рода вещи на с/c++ обычно делают
                                                                                                                        +1
                                                                                                                        Сам по себе Rust кроссплатформенный, Win/Linux/MacOS точно поддерживаются.
                                                                                                                        Ничего слишком серьёзного писать на нём не приходилось, но все мои «экспериментальные» программы без проблем собирались и работали и на Windows, и на Linux.
                                                                                                                        Единственное, с чем столкнулся: некоторые/многие крейты, связанные с GUI, могут не поддерживать всю тройку ОСей.
                                                                                                                      0

                                                                                                                      А как у Rust с кроссплатформенностью? Можно и собрать бинарники для Windows/FreeBSD/Linux в, скажем, OpenBSD? Или придется сотни toolchain'ов искать и ставить непонятно откуда?

                                                                                                                        +1
                                                                                                                        Rust поддерживает кросскомпиляцию официально, а если воспользоватmся, например, cross — это даже довольно удобно (при условии, что у вас есть Docker/Podman).
                                                                                                                        0

                                                                                                                        Расскажите пожалуйста об областях применения на практике


                                                                                                                        Например, что насчёт создания HTTP API.
                                                                                                                        Или создания микросервиса, который бы слушал из и писал в Kafka.


                                                                                                                        Спасибо

                                                                                                                          +2

                                                                                                                          Про HTTP — смотрите сюда: https://actix.rs/docs/getting-started
                                                                                                                          Для Kafka есть обертка над librdkafka: https://github.com/fede1024/rust-rdkafka

                                                                                                                            +2

                                                                                                                            Области применения весьма широкие. Например, вот что делал я на Rust:


                                                                                                                            • Web-сервисы: http, gPRC, WebSocket (в том числе и общался с Kafka). Как крупные web-приложения, так и небольшие.
                                                                                                                            • Web-сервер.
                                                                                                                            • Web-клиенты.
                                                                                                                            • Фронтэнд под WASM в браузере.
                                                                                                                            • Внебраузерные WASM-модули под wasmer.
                                                                                                                            • Консольные утилиты.
                                                                                                                            • Библиотеки и модули для других языков (PHP).
                                                                                                                            • GUI-библиотеку и игру на ней.
                                                                                                                            • Смарт-контракты для блокчейна (Solana, она сама тоже написана на Rust).
                                                                                                                            • Макросы и "скрипты" сборки для автоматизации процесса разработки.

                                                                                                                            Еще хочу попробовать мобильную разработку на Rust, но пока с этим есть некоторые трудности.

                                                                                                                              0

                                                                                                                              Спасибо большое


                                                                                                                              Есть пример веб-проекта, у которого бэкенд полностью был бы сделан на Rust?
                                                                                                                              Open-source bootstrap?


                                                                                                                              Может ли Rust быть заменой языкам высокого уровня?


                                                                                                                              Есть ли там стандартные обвязки типа ORM, логирование, сбор метрик в прометеус, работа с Redis, авторизация и т.п.


                                                                                                                              Несколько полна стандартная библиотека?
                                                                                                                              Прочесть файл, читать данные из TCP-запроса, держать HTTP-соединение и т.п.

                                                                                                                                +3
                                                                                                                                Есть пример веб-проекта, у которого бэкенд полностью был бы сделан на Rust?

                                                                                                                                Ну чтобы далеко не ходить — вот вам пример веб-приложения, бэкенд которого на Rust: https://utex.io/exchange-pro


                                                                                                                                Для подобных задач Rust показывает себя хорошей заменой C++ и Java/Kotlin. Вообще, я бы предпочел Rust любому высокоуровнему языку из мейнстримных сегодня. Но из-за незрелости в некоторых нишах его использование все еще затруднено (как, например, в мобильной разработке). Хотя именно с точки зрения языка нет принципиальных проблем для его распространения в эти ниши.


                                                                                                                                ORM в Rust отличается от того, как он реализуется в мейнстримных ООП-языках. Более простой и с растовой спецификой (многие вещи из рантайма выносятся на стадию компиляции). Самая близкая и зрелая реализация — это Diesel. Он может почти все, только плоховато документирован. Хотя для большого количества случаев достаточно sqlx.


                                                                                                                                Логирование — есть куча неплохих библиотек, полный список здесь. Сбор метрик в прометеус, работа с Redis и RocksDB и т.д. — все это есть, чаще в виде безопасных оберток над Сишными либами.


                                                                                                                                Стандартная библиотека очень хорошая, но она довольно минималистичная. Работа с сетью, с файловой системой — это, конечно, есть, но, например, полноценного веб-сервера вы в ней не найдете. Для этого есть отдельные крейты, такие как hyper, actix-web, tokio и так далее. Даже фасад для логирования, функционал сериализации/десериализации и работа с регулярными выражениями вынесены в отдельные крейты, которые становятся стандартами де-факто для использования: log, serde, regex и прочие. Вот список всех крейтов по количеству загрузок за все время.

                                                                                                                                  0
                                                                                                                                  Походил по ссылкам, почитал, добавил некоторые вещи в закладки, спасибо :)

                                                                                                                                  Можете ли рассказать подробнее про использование Rust в utex.io?

                                                                                                                                  Меня интересует архитектура вида
                                                                                                                                  * API Gateway
                                                                                                                                  * Kafka
                                                                                                                                  * воркеры с бизнес-логикой (слушают стримы Kafka, и туда же пишут)

                                                                                                                                  Не нашёл гейтвея на Rust, но туда вполне можно поставить опенсорс на Golang
                                                                                                                                  А вот воркеры на первый взгляд как раз без проблем можно писать на Rust
                                                                                                                            +1
                                                                                                                            По моему мнению примерно 85% текущей ценности Rust содержится именно в cargo.
                                                                                                                            Именно cargo делает ту работу, которая сейчас унифицировано не делается в C/C++:
                                                                                                                            1) центральный репозиторий модулей (crate), а не отдельно каждый модуль из интернета
                                                                                                                            2) сборка проекта с зависимостями (здесь очень важное, что все другие проекты тоже собираются тем же способом, а не разными make, cmake, qmake и т.п.)
                                                                                                                            3) встроенные: модульное тестирование, форматирование кода и статический анализатор
                                                                                                                              +1

                                                                                                                              Мейнстримные языки, более современные, чем C/C++, этим не удивишь.

                                                                                                                            Only users with full accounts can post comments. Log in, please.