Почему структура должна быть инициализирована в ржавчине? - PullRequest
0 голосов
/ 17 апреля 2020

В C Я могу использовать структуру, которая еще не была инициализирована. Я пробовал этот код в Rust:

struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

fn main(){
    let mut user1: User;
    user1.active = false;
}

Но он выдал ошибку компиляции:

error[E0381]: assign to part of possibly-uninitialized variable: `user1`
  --> src/main.rs:10:5
   |
10 |     user1.active = false;
   |     ^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `user1`

Почему это разрешено в C, но ошибка в Rust?

Ответы [ 2 ]

10 голосов
/ 17 апреля 2020

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

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

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

В C вы можете получить доступ к этим значениям; тем самым позволяя компилятору неправильно компилировать ваш код, поскольку вы нарушили контракт. Однако в Rust вам не разрешено это делать.

В некоторых языках, таких как C#, неинициализированные значения заменяются на null. У нас похожая концепция: Option s, которые либо Some(value), либо есть None.


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


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

Используйте std::mem::MaybeUninit и , прочитайте Romic nomicon , прежде чем копаться в unsafe.

2 голосов
/ 17 апреля 2020

Как уже говорил Оптимисти c Пич, это в основном то, как работает Rust. Все должно быть инициализировано в Rust. То же самое относится и к любой другой переменной.

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

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

Вероятно, причиной этого выбора дизайна является то, что в Rust есть несколько типов, где нет очевидных значений по умолчанию. На других языках, таких как C#, у вас есть значение null, которое можно присвоить всем ссылкам. В Rust вы можете получить нечто похожее на null, используя Option<T> в качестве типа (вместо просто T) и присваивая значение None. Но это работает, только если программист решил использовать Option<T> вместо T. Каким может быть значение по умолчанию для переменной типа std::fs::File, если в Rust нет null и программист не определил начальное значение?

...