Обновить
16

Пользователь

1
Подписчики
Отправить сообщение

Вот любят в рунете взять и обосрать на ровном месте. Написать язвительную грубость вместо нормального комментария.
Не знаю как это объяснить - наследие совка?

Чтобы ещё раз ненавязчиво намекнуть, что бедную девочку угнетают?

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

Ну знаете, в том же c++ эту элементарную вещь тоже только в 17 издании добавили. Наверное не всё там так просто

Допустим у нас вредоносное вложение, которое должно вызывать чтение за пределами массива. C++ позволит прочитать данные за пределами массива, Rust не позволит.
Или например Rust сразу позволит отловить некоторые ошибки в логике (например, не позволит создать ситуацию где мы читаем из висячего указателя).

Нейроночная статья (привет m-dash) для рекламы курсов

Да, посмотрел по этому вопросу - раст сейчас не гарантирует copy elision, что иногда приводит к переполнению стека в случае больших структур (структура снача создаётся на стеке, потом только копируется на кучу). Иногда оптимизатор такую ситуацию исключает, но понятное дело опираться на оптимизатор это дело ненадёжное. Пока что единственный 100% способ создать большую структуру сразу на куче это в unsafe блоке самому выделить память и потом её инициализировать. Что-то вроде этого:

let my_box = unsafe {
            // выделяем
            let ptr = alloc::alloc(alloc::Layout::new::<MyType>()) as *mut MyType;
            
            // ...инициализируем

            // кладём в box
            Box::from_raw(ptr)
};

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

А какой текст паники? У меня не вопроизводится локально (на плейграунде тоже https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=63726b68a378e42b25a3d240fc73f825)

Правда, если вдруг нужен будет 1000-й элемент, строчка выйдет длинная

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

if let [a, .., b] = &mut vec[1..1000] {
    a.push_str(b);
}

А что делать с хэшмэпами?

Да, здесь сложность, потому что хэшмапу не задерефишь в какой-то базовый тип (как Vec в слайс). Без unsafe изящно не вижу как это сделать. Как вам предложил ИИ придётся доставать значение из мапы (через Option, remove или std::mem::replace) и класть обратно.
Имхо ваш пример проще просто в unsafe сделать, логика более прямая получается

let set = unsafe {
    hashmap.get(chosen)
        .and_then(|c| (c as *const BitSet).as_ref())
        .unwrap()
};
for (name, item) in hashmap.iter_mut() {
    if name != chosen {
        *item = item.intersect(set);
    }
}

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

  1. Без unsafe

  2. Без методов для обхода бороу чекера на vec (get_disjoint_mut / split_at_mut / etc.)

fn main() {
    let mut vec = vec![
        "foo".to_string(), 
        "bar".to_string(),
        "jar".to_string(),
        "fizz".to_string(),
        "buzz".to_string(),
    ];
    // складываем первый и второй
    if let [foo, bar, ..] = &mut vec[..] {
        foo.push_str(bar);
    }
    // или например второй и четвёртый
    if let [bar, .., fizz] = &mut vec[1..4] {
        bar.push_str(fizz);
    }
    println!("{:?}", vec);
}

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

(вы так и не объяснили, чем это опасно, но, допустим, чем-то опасно)

Вот вы привели пример с конкатенацией строк. Алгоритм конкатенации условно такой (на псевдоСи):

struct string {
  inner *u8
  size usize
}
int concat(this *string, other *string) {
  *u8 new_buf = (*u8)realloc(this.inner, this.size + other.size)
  if new_buf == NULL_PTR {
    return -1
  }
  // если this и other это одна и та же строка, 
  // то на момент вызова memcpy обращение к other.inner
  // это потенциально use after free
  memcpy(new_buf + this.size, other.inner, other.size)
  this.inner = new_buf
  this.size = this.size + other.size
  return 0
}

Чтобы себе в ногу не стрелять

Но как бы вопрос в соотношении. Вы так риторически заявляете "ничего без unsafe не получится".
Только вот по опыту если пришлось применить unsafe, то соотношение будет 50 unsafe строчек на 10000 safe строчек.

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

Да-да, просто угроза национальной безопасности, как минимум!

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

А если какой-то другой контейнер?

Да, с этим есть сложности. Но всегда как крайняя опция есть unsafe, где вы берёте на себя гарантии безопасности. Также не вижу проблемы с этим. У многих людей это какой-то красный флаг что "о, это нельзя сделать в safe rust", но я не понимаю почему это проблема. Это просто показывает что в каких-то сложных ситуациях нельзя доказать безопасность статическим анализом компилятора и приходится брать риск на себя (как в любом другом языке).

И кстати, вот так уже внезапно стало безопасным

Ну да, я знаю что бороу чекер умеет видеть, что бы обращаетесь к разным полям структуры и не жалуется. Что вы хотели этим сказать?
Такое же он не даст сделать
x.foo += &x.foo;

Защищает это от того, что вы могли написать

vec[0] += &vec[0];

Что уже небезопасно.
Не вижу в данном случае проблемы в использовании split_at_mut, чтобы гарантировать, что вы будете писать и редактировать одну и ту же часть вектора.
Да, бороу чекер не может различить что вас случай безопасный. Но это не является его врождённым недостатком и может быть исправлено в будущем. Просто он недостаточно тонко умеет определять безопасные сценарии.

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

По дефолту Rust генерирует код деструктора для структуры рекурсивно. Сначала вызывается drop для полей, потом выполняется ваш код в Drop.

Вроде как наоборот - сначала вызывается наш Drop, потом drop для полей. Но м.б. вы что-то другое имели в виду.

Но в целом статья хорошая.

Ваш пакет errors я в другой ветке уже разробрал https://habr.com/ru/articles/980752/comments/#comment_29328330.
Не даёт он нормальных способов для работы с ошибками.

Ну тогда расскажите как в го правильно работать с ошибками. Вот так сможете:

  1. только с помощью стандартной библиотеки

  2. используемые функции/методы не должны принимать any в аргументах

  3. чтобы я мог полученную ошибку привести из error к конкретному типу, но не вызывая руками type assertion

?

Это во первых.

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

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

Информация

В рейтинге
5 568-й
Зарегистрирован
Активность

Специализация

Бэкенд разработчик
Средний
Rust