LINUX.ORG.RU

Rust 1.91.0

 ,


0

6

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

Список изменений:

  • aarch64-pc-windows-msvc теперь является платфомой первого уровня поддержки (ранее было второго уровня). По сравнению со вторым уровнем поддержки, первый уровень подразумевает обязательное успешное прохождения всех тестовых наборов на платформе.

  • Добавлена проверка линтера при возвращения из функции «висячего» указателя. Встроенный в компилятор Borrow Checker уже имеет проверку на тот случай, когда возвращаяется «висячая» ссылка, но это не работало при использовании сырых указателей. Теперь будет сгенерировано предупреждение:

fn f() -> *const u8 {
    let x = 0;
    &x
}
warning: a dangling pointer will be produced because the local variable `x` will be dropped
 --> src/lib.rs:3:5
  |
1 | fn f() -> *const u8 {
  |           --------- return type of the function is `*const u8`
2 |     let x = 0;
  |         - `x` is part the function and will be dropped at the end of the function
3 |     &x
  |     ^^
  |
  = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated
    at the end of the function because nothing is referencing it as far as the type system is
    concerned
  = note: `#[warn(dangling_pointers_from_locals)]` on by default

В разряд стабильного API было переведено:

  • Path::file_prefix
  • AtomicPtr::fetch_ptr_add
  • AtomicPtr::fetch_ptr_sub
  • AtomicPtr::fetch_byte_add
  • AtomicPtr::fetch_byte_sub
  • AtomicPtr::fetch_or
  • AtomicPtr::fetch_and
  • AtomicPtr::fetch_xor
  • {integer}::strict_add
  • {integer}::strict_sub
  • {integer}::strict_mul
  • {integer}::strict_div
  • {integer}::strict_div_euclid
  • {integer}::strict_rem
  • {integer}::strict_rem_euclid
  • {integer}::strict_neg
  • {integer}::strict_shl
  • {integer}::strict_shr
  • {integer}::strict_pow
  • i{N}::strict_add_unsigned
  • i{N}::strict_sub_unsigned
  • i{N}::strict_abs
  • u{N}::strict_add_signed
  • u{N}::strict_sub_signed
  • PanicHookInfo::payload_as_str
  • core::iter::chain
  • u{N}::checked_signed_diff
  • core::array::repeat
  • PathBuf::add_extension
  • PathBuf::with_added_extension
  • Duration::from_mins
  • Duration::from_hours
  • impl PartialEq<str> for PathBuf
  • impl PartialEq<String> for PathBuf
  • impl PartialEq<str> for Path
  • impl PartialEq<String> for Path
  • impl PartialEq<PathBuf> for String
  • impl PartialEq<Path> for String
  • impl PartialEq<PathBuf> for str
  • impl PartialEq<Path> for str
  • Ipv4Addr::from_octets
  • Ipv6Addr::from_octets
  • Ipv6Addr::from_segments
  • impl<T> Default for Pin<Box<T>> where Box<T>: Default, T: ?Sized
  • impl<T> Default for Pin<Rc<T>> where Rc<T>: Default, T: ?Sized
  • impl<T> Default for Pin<Arc<T>> where Arc<T>: Default, T: ?Sized
  • Cell::as_array_of_cells
  • u{N}::carrying_add
  • u{N}::borrowing_sub
  • u{N}::carrying_mul
  • u{N}::carrying_mul_add
  • BTreeMap::extract_if
  • BTreeSet::extract_if
  • impl Debug for windows::ffi::EncodeWide<'_>
  • str::ceil_char_boundary
  • str::floor_char_boundary
  • impl Sum for Saturating<u{N}>
  • impl Sum<&Self> for Saturating<u{N}>
  • impl Product for Saturating<u{N}>
  • impl Product<&Self> for Saturating<u{N}>

Признак const добавлен к следующим функциям:

  • <[T; N]>::each_ref
  • <[T; N]>::each_mut
  • OsString::new
  • PathBuf::new
  • TypeId::of
  • ptr::with_exposed_provenance
  • ptr::with_exposed_provenance_mut

>>> Подробнее

★★★

Проверено: hobbit ()
Последнее исправление: snake266 (всего исправлений: 1)
Ответ на: комментарий от kaldeon

Кого депрекейтить? 1.91? Если зайти на crates.io и выбрать самый скачаваемый пакет (syn), то там минимально поддерживаемая версия компилятора 1.68, которая вышла два года назад. Если мы возьмем serde для сериализации десериализации, то там будет указана 1.56, которая вышла четыре года назад

snake266 ★★★
() автор топика

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

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

unC0Rr ★★★★★
()
Ответ на: комментарий от usi_svobodi

Это уже будет зависит от мейнтейнеров Ubuntu, а не от раста или разработчиков uutils. Но это уже обсудили в теме про Ubuntu

snake266 ★★★
() автор топика
Ответ на: комментарий от unC0Rr

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

snake266 ★★★
() автор топика
Последнее исправление: snake266 (всего исправлений: 1)
Ответ на: комментарий от Bad_ptr

Я еще не трогал мультитрединг на расте, но типажи Send и Sync выглядит очень интересно, потому что получается что безопасность передачи переменной между потоками у тебя заложена прямо в типе.

https://doc.rust-lang.org/book/ch16-04-extensible-concurrency-sync-and-send.html

Но я не сварщик: я на расте только пару cli утилит писал

snake266 ★★★
() автор топика
Последнее исправление: snake266 (всего исправлений: 1)
Ответ на: комментарий от Bad_ptr
// gcc -pthread race.c && ./a.out
#include <pthread.h>
#include <stdio.h>

#define N 4
#define ITERS 1000000

int counter = 0; // shared, non-atomic

void* worker(void* _) {
    for (int i = 0; i < ITERS; i++) {
        counter++; // racy: read-modify-write without synchronization
    }
    return NULL;
}

int main(void) {
    pthread_t t[N];
    for (int i = 0; i < N; i++) pthread_create(&t[i], NULL, worker, NULL);
    for (int i = 0; i < N; i++) pthread_join(t[i], NULL);
    printf("counter = %d (expected %d)\n", counter, N * ITERS);
    return 0;
}

Результат запуска:

counter = 1000000 (expected 4000000)

Копия кода, но на расте:

use std::thread;

fn main() {
    let mut counter = 0;
    let c = &mut counter; // one mutable reference

    let mut handles = Vec::new();
    for _ in 0..4 {
        // try to share the same &mut across threads
        handles.push(thread::spawn(move || {
            for _ in 0..1_000_000 {
                *c += 1; // would be a race if allowed
            }
        }));
    }

    for h in handles { h.join().unwrap(); }
    println!("counter = {}", counter);
}

Не компилится:

error[E0597]: `counter` does not live long enough
  --> main.rs:5:13
   |
4  |       let mut counter = 0;
   |           ----------- binding `counter` declared here
5  |       let c = &mut counter; // one mutable reference
   |               ^^^^^^^^^^^^ borrowed value does not live long enough
...
10 |           handles.push(thread::spawn(move || {
   |  ______________________-
11 | |             for _ in 0..1_000_000 {
12 | |                 *c += 1; // would be a race if allowed
13 | |             }
14 | |         }));
   | |__________- argument requires that `counter` is borrowed for `'static`
...
19 |   }
   |   - `counter` dropped here while still borrowed
unC0Rr ★★★★★
()
Ответ на: комментарий от unC0Rr

Если бы софт IRS для Ариан4/5 писали на расте, ракета бы не навернулась. Впрочем, и на плюсах тоже было бы ОК.

seiken ★★★★★
()
Ответ на: комментарий от rumgot

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

snake266 ★★★
() автор топика
Ответ на: комментарий от unC0Rr

В крестах довольно просто прикручивается обработка аппаратных исключений.

Пример: https://stackoverflow.com/questions/457577/catching-access-violation-exceptions

Как из обработчиков аппаратных исключений правильно кидать C++ исключение: https://stackoverflow.com/questions/36154589/throwing-c-exceptions-from-a-hardware-exception-handler-why-does-fnon-call-e

timdorohin ★★★★
()
Последнее исправление: timdorohin (всего исправлений: 3)

Забыли метку танцпол добавить

mrdeath ★★★★★
()
Ответ на: комментарий от unC0Rr

Как я понял, там было переполнение из-за конверсии float64->int16 (или uint16…, но это не важно). В случае переполнения Ада кидала исключение, которое тупо не обрабатывалось программистами по причинам производительности.

Причём, переполение было в коде, который инициализировал систему IRS, и который в процессе полёта был не нужен, но по какой-то причине продолжал работать в полёте. И поскольку этот стартовый код выполнялся в том же процессе, что и основной код IRS, терминировался весь софт IRS. На запасном модуле IRS произошла та же ошибка, потому что во float64 хранилась скорость.

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

seiken ★★★★★
()
Последнее исправление: seiken (всего исправлений: 1)

«Страшную весть принёс я в твой дом, Надежда. Зови детей⁠⁠...»

Smacker ★★★★★
()
Ответ на: комментарий от unC0Rr

`counter` does not live long enough

Серьёзно? Именно в этом ошибка в Сишном варианте была?
Это те самые знаменитые растовские понятные сообщения об ошибках, которые сами подсказывают тебе как исправить код?

Bad_ptr ★★★★★
()

Когда эта хрень перестанет засирать диск до отказа при сборке? В системе и jail'е одновременно этой гадости уже мало 30 ГБ.

IPR ★★★★★
()

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

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

seiken ★★★★★
()
Ответ на: комментарий от Bad_ptr

Серьёзно?

А что в этом несерьёзного?

Именно в этом ошибка в Сишном варианте была?

Нет, не в этом. Я в расте не все ошибки выписал, которые компилятор сказал, только первую.

Это те самые знаменитые растовские понятные сообщения об ошибках, которые сами подсказывают тебе как исправить код?

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

unC0Rr ★★★★★
()
Ответ на: комментарий от unC0Rr

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

Почему рустеры скрывают от нас информацию?

В первую же очередь ошибка предотвратила рейс в многопотоке

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

Bad_ptr ★★★★★
()
Ответ на: комментарий от unC0Rr

А зачем ты в системе хранишь артефакты сборки?

Я не храню, они появляются во время сборки portmaster'ом и до make clean.

IPR ★★★★★
()
Ответ на: комментарий от Bad_ptr

Почему рустеры скрывают от нас информацию?

Код приложен, делай что хочешь с ним. Но раз так сложно, то вот: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=44769ef58894d8246a96c340630b3868

проблема в одновременном доступе. И заявляешь что руст эту проблему решает

Ну натурально, ты же не можешь скомпилировать код с датарейсом. Решает.

unC0Rr ★★★★★
()
Ответ на: комментарий от unC0Rr

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

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

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

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

ox55ff ★★★★★
()
Ответ на: комментарий от unC0Rr

Результат запуска: counter = 1000000 (expected 4000000)

Результат предсказуем если ты доступ к данным не синхронизируешь.

Вариант с мютексами:

#include <pthread.h>
#include <stdio.h>

#define N 4
#define ITERS 1000000

int counter = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void* worker(void* _) {
    for (int i = 0; i < ITERS; i++) {
        pthread_mutex_lock(&lock);
        counter++;
        pthread_mutex_unlock(&lock);
    }
    return NULL;
}

int main(void) {
    pthread_t t[N];
    for (int i = 0; i < N; i++) pthread_create(&t[i], NULL, worker, NULL);
    for (int i = 0; i < N; i++) pthread_join(t[i], NULL);
    printf("counter = %d (expected %d)\n", counter, N * ITERS);
    return 0;
}

Вариант с атомиками:

#include <pthread.h>
#include <stdio.h>
#include <stdatomic.h>

#define N 4
#define ITERS 1000000

atomic_int counter = 0;

void* worker(void* _) {
    for (int i = 0; i < ITERS; i++) {
                atomic_fetch_add(&counter, 1);
    }
    return NULL;
}

int main(void) {
    pthread_t t[N];
    for (int i = 0; i < N; i++) pthread_create(&t[i], NULL, worker, NULL);
    for (int i = 0; i < N; i++) pthread_join(t[i], NULL);
    printf("counter = %d (expected %d)\n", counter, N * ITERS);
    return 0;
}
$ cc -lpthread 1.c
./a.out
counter = 4000000 (expected 4000000)

Только вот если тоже самое сделать на расте (код поправил чатжопате):

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = Vec::new();

    for _ in 0..4 {
        let counter = Arc::clone(&counter);
        handles.push(thread::spawn(move || {
            for _ in 0..1_000_000 {
                *counter.lock().unwrap() += 1;
            }
        }));
    }

    for h in handles { h.join().unwrap(); }

    println!("counter = {}", *counter.lock().unwrap());
}

…выполняемый код окажется более чем в 2 раза тормозней:

rust:

$ /usr/bin/time ./rust
counter = 4000000
        0,93 real         1,47 user         1,84 sys

C mutex:

$  /usr/bin/time ./c-mutex
counter = 4000000 (expected 4000000)
        0,43 real         0,36 user         1,06 sys

C atomic:

$ /usr/bin/time ./c-atomic
counter = 4000000 (expected 4000000)
        0,10 real         0,36 user         0,00 sys

Только вот…

$ ls -lah rust c-atomic
-rwxr-xr-x  1 iron iron  6,3K 31 окт.  22:17 c-atomic
-rwxr-xr-x  1 iron iron  582K 31 окт.  22:04 rust
iron ★★★★★
()
Ответ на: комментарий от snake266

Я намеренно поскромничал в описании проекта, потому что знаю что некоторых может тригерить расписывание какой раст «крутой, современный и молодежный».

Синтаксис его немного напрягает. Конечно меньше, чем Python и Perl, но таки сишечка при всей её примитивности выглядит куда приятнее и роднее, чем этот коцмический набор ржавых иероглифов.

А что нынче с транспайлерами в Rust? Почему его до сих пор нет в качестве таргета для Haxe?!

И как обстоят дела с другими альтернативными безопасными плюсиками?

sanyo1234
()
Последнее исправление: sanyo1234 (всего исправлений: 2)
Ответ на: комментарий от ox55ff

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

А в компайл-тайме борроу-чекер. С нулевыми затратами в рантайме.

контрятся другими подходам

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

Достаточно любого языка с подсчётом ссылок.

Угу, с подсчётом ссылок, толстым рантаймом, сборщиком мусора…

unC0Rr ★★★★★
()
Ответ на: комментарий от iron

У меня другие результаты:

> hyperfine --warmup 20 --runs 50 ./c-mutex ./rust-mutex
Benchmark 1: ./c-mutex
  Time (mean ± σ):     190.9 ms ±  14.2 ms    [User: 237.5 ms, System: 413.4 ms]
  Range (min … max):   158.8 ms … 220.8 ms    50 runs
 
Benchmark 2: ./rust-mutex
  Time (mean ± σ):     256.1 ms ±  35.3 ms    [User: 903.7 ms, System: 92.4 ms]
  Range (min … max):   205.9 ms … 318.5 ms    50 runs
 
Summary
  ./c-mutex ran
    1.34 ± 0.21 times faster than ./rust-mutex

В расте другая реализация мютексов, поэтому всё возможно.

С атомиками ещё интереснее:

> hyperfine --warmup 20 --runs 50 ./c-atomic ./rust-atomic 
Benchmark 1: ./c-atomic
  Time (mean ± σ):      33.7 ms ±   3.1 ms    [User: 128.5 ms, System: 0.2 ms]
  Range (min … max):    26.2 ms …  43.4 ms    50 runs
 
Benchmark 2: ./rust-atomic
  Time (mean ± σ):      33.4 ms ±   3.0 ms    [User: 127.5 ms, System: 0.6 ms]
  Range (min … max):    27.5 ms …  40.7 ms    50 runs
 
Summary
  ./rust-atomic ran
    1.01 ± 0.13 times faster than ./c-atomic
unC0Rr ★★★★★
()
Ответ на: комментарий от ertaquo

Да мы вообще не атомики и мютексы обсуждали, программа была приведена как пример того, что раст не даёт скомпилить код с datarace.

unC0Rr ★★★★★
()
Ответ на: комментарий от hateyoufeel

Ну всё, теперь сишечке точно капец!

Кстати, вопрос «знатокам»: а есть уже компилятор C/C++, переписанный на Rust? ;))

Интересно же!.. ;P ;))

Somebody ★★★
()
Ответ на: комментарий от Somebody

Насколько я понял, они пока даже свой компилятор неосилили. Чтобы скомпилить rust, нужно сначала скомпилить llvm, который потом соберёт rust, который потом соберёт три с половиной библиотеки, нужные в системе.

shell-script ★★★★★
()

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

Не освобождает, а просто заменяет ручное управление памятью в рамках поддержания пар malloc/free, на ручную модификацию кода чтобы тот проходил боровчекер. Это нельзя сравнивать влоб, но и говорить что там всё за тебя само, не надо =)

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от iron

Слишком малое количество итераций для корректного изменения времени. Делал как-то похожую хрень с атомиками на го. На 8 ядернике получалось что-то толи 100 млн толи 1 млрд итераций в секунду

cobold ★★★★★
()
Ответ на: комментарий от shell-script

Насколько я понял, они пока даже свой компилятор неосилили.

Печально... :(

Но показательно, как мне кажется. ;P ;))

Чтобы скомпилить rust, нужно сначала скомпилить llvm, который потом соберёт rust, который потом соберёт три с половиной библиотеки, нужные в системе.

«Как трудно жить!»... © :))))

Somebody ★★★
()
Ответ на: комментарий от iron

код поправил чатжопате

Так что ж ты и код для сей сгенерировать тебе не попросил?

Мьютексы

use std::sync::Mutex;
use std::thread;

const N: usize = 4;
const ITERS: usize = 1000_000;

static COUNTER: Mutex<u32> = Mutex::new(0);

fn main() {
    let mut handles = Vec::with_capacity(N);

    for _ in 0..N {
        handles.push(thread::spawn(move || {
            for _ in 0..ITERS {
                let mut counter = COUNTER.lock().unwrap();
                *counter += 1;
            }
        }));
    }

    for h in handles {
        h.join().unwrap();
    }

    println!("counter = {}", *COUNTER.lock().unwrap());
}

Атомики

use std::sync::atomic::{AtomicU32, Ordering};
use std::thread;

const N: usize = 4;
const ITERS: usize = 1000_000;

static COUNTER: AtomicU32 = AtomicU32::new(0);

fn main() {
    let mut handles = Vec::with_capacity(N);

    for _ in 0..N {
        handles.push(thread::spawn(move || {
            for _ in 0..ITERS {
                COUNTER.fetch_add(1, Ordering::Relaxed);
            }
        }));
    }

    for h in handles {
        h.join().unwrap();
    }

    println!("counter = {}", COUNTER.load(Ordering::Relaxed));
}

Результаты бенчмарков

hyperfine --warmup 20 --runs 50 ./c_mutex rust_mutex/target/release/rust_mutex
Benchmark 1: ./c_mutex
  Time (mean ± σ):     186.8 ms ±   8.0 ms    [User: 423.4 ms, System: 265.4 ms]
  Range (min … max):   154.0 ms … 195.9 ms    50 runs

  Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.

Benchmark 2: rust_mutex/target/release/rust_mutex
  Time (mean ± σ):     167.7 ms ±   7.5 ms    [User: 396.2 ms, System: 235.0 ms]
  Range (min … max):   125.9 ms … 177.2 ms    50 runs

Summary
  rust_mutex/target/release/rust_mutex ran
    1.11 ± 0.07 times faster than ./c_mutex
hyperfine --warmup 20 --runs 50 ./c_atomics rust_atomics/target/release/rust_atomics
Benchmark 1: ./c_atomics
  Time (mean ± σ):      74.1 ms ±   5.7 ms    [User: 268.3 ms, System: 0.5 ms]
  Range (min … max):    65.8 ms …  81.4 ms    50 runs

Benchmark 2: rust_atomics/target/release/rust_atomics
  Time (mean ± σ):      72.8 ms ±   5.3 ms    [User: 260.7 ms, System: 0.7 ms]
  Range (min … max):    66.1 ms …  79.3 ms    50 runs

Summary
  rust_atomics/target/release/rust_atomics ran
    1.02 ± 0.11 times faster than ./c_atomics
Darfin
()
Ответ на: комментарий от mx__

Он очень популярен в комментариях на LOR'е... ;))

Somebody ★★★
()
Ответ на: комментарий от unC0Rr

Не компилится

Т.е. если мне нужно намерено получится поведение как в примере на сях, я просто не смогу скомпилить программу на ржавом? Какой хороший ЯП этот ржавый (на самом деле нет)

foror ★★★★★
()
Ответ на: комментарий от unC0Rr

А потом люди с воем бегут из разработки, рассказывая как боров крутил им руки.

LongLiveUbuntu ★★★★★
()

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

One ★★★★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.