Почему изменчивость переменной не отражена в сигнатуре ее типа в Rust? - PullRequest
5 голосов
/ 13 января 2020

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

let ref_foo : &i32 = &foo;
let mut ref_bar : &i32 = &bar;

Почему это так? Это кажется довольно серьезным упущением. Я имею в виду, что даже C / C ++ делает это более явно, имея два const, чтобы указать, что у нас есть const указатель на const данные:

const int * const ptr_foo = &foo;
const int * ptr_bar = &bar;

Есть ли лучший способ думать о это?

Ответы [ 3 ]

11 голосов
/ 13 января 2020

Изменчивость - это свойство привязки в Rust, а не свойство типа .

Единственный владелец значения всегда может изменить его, перемещая это к изменяемой привязке:

let s = "Hi".to_owned();  // Create an owned value.
s.push('!');              // Error because s is immutable.
let mut t = s;            // Move owned value to mutable binding.
t.push('!');              // Now we can modify the string.

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

Изменчивость ссылок ортогональна изменчивости привязок. Rust использует одно и то же ключевое слово mut для устранения неоднозначности двух типов ссылок, но это отдельная концепция.

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

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

let mut x = ...;
// modify x ...
let x = x;

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

3 голосов
/ 13 января 2020

Константы в C ++ и Rust принципиально разные. В C ++ constness это свойство любого типа, а в Rust это свойство ссылки. Таким образом, в Rust нет истинных константных типов.

Возьмем, к примеру, этот код C ++:

void test() {
    const std::string x;
    const std::string *p = &x;
    const std::string &r = x;
}

Переменная x объявлена ​​с типом константы, поэтому любая ссылка, созданная на нее, будет быть также постоянным, и любая попытка изменить его (с помощью const_cast для экзамена) приведет к неопределенному поведению . Обратите внимание, что const является частью типа объекта.

Однако в Rust нет способа объявить постоянную переменную:

fn test() {
    let x = String::new();
    let r = &x;

    let mut x = x; //moved, not copied, now it is mutable!
    let r = &mut x;
}

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

Потому что, когда вы объявляете локальную переменную, в C ++ или Rust, вы на самом деле делаете две вещи:

  • Создание самого объекта.
  • Объявление имени для доступа к объекту, ссылка своего рода.

Когда вы пишете константу C ++, вы делаете обе константы Объект и ссылка. Но в Rust нет постоянных объектов, поэтому только ссылка постоянна. Если вы перемещаете объект, вы удаляете исходное имя и связываете его с новым, которое может изменяться или не изменяться.

Обратите внимание, что в C ++ нельзя перемещать постоянный объект, он останется постоянным навсегда. Но в

о наличии двух consts для указателей, они одинаковы в Rust, если у вас есть два косвенных направления:

fn test() {
    let mut x = String::new();
    let p: &mut String = &mut x;
    let p2: &&mut String = &p;
}

О том, что лучше, это вопрос попробовать, но запомнить все странные вещи, которые константа может делать в C ++:

  • Постоянный объект всегда постоянен, кроме случаев, когда это не так: конструкторы и деструкторы.
  • Константа класс с изменяемыми членами не является действительно постоянным. mutable не является частью системы типов, в то время как Rust Cell/RefCell.
  • Класс с константным членом - трудная задача: конструкторы по умолчанию и операторы копирования / перемещения не работают.
0 голосов
/ 13 января 2020

В C ++ все изменяемо по умолчанию, а ключевое слово const указывает на то, что вы хотите изменить это поведение.

В Rust все является изменяемым im по умолчанию, а mut Ключевое слово * означает, что вы хотите изменить это поведение.

Обратите внимание, что для указателей Rust требует либо ключевое слово mut, либо const:

let ref_foo : *const i32 = &foo;
let mut ref_bar : *const i32 = &bar;

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

даже C / C ++ делает это лучше

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

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