В вашем примере p
и q
действительно неизменны, но затем вы перемещаете их в экземпляр Line
с помощью конструктора, поскольку они передаются по значению и не реализуют Copy
для включения неявное копирование. Это означает, что исходные привязки (p
и q
) больше не действительны (компилятор не позволит вам их использовать), а значения доступны только через изменяемую привязку line
, которая позволяет изменять члены. По сути, это не значения , которые могут изменяться, а их привязки. Например, следующий код можно использовать для повторной привязки значения для изменения его изменчивости:
let x = String::from("hello world"); // using String as an example of a non-Copy type
let mut x = x; // this shadows the previous binding with a mutable one of the same name
x.make_ascii_uppercase(); // we can now mutate the string
let x = x; // shadow the mutable binding with an immutable one
println!("Result: {}", x);
Этот пример работает, поскольку мы имеем прямой контроль над значением и можем перемещать / связывать его по своему усмотрению. Введение ссылок ограничит то, что может быть сделано - например, следующие примеры не будут работать:
let x = String::from("hello world");
let x_ref = &x; // create an immutable reference to x
let mut x_mut = x; // error - we can't move x while it's borrowed
let x_mut_ref = &mut x; // error - we can't create a mutable reference while any other references exist
Я бы рекомендовал прочитать владение и переместить страницу Rust на пример, что объясняет это очень хорошо.