Sự khác biệt giữa việc đặt “mut” trước tên biến và sau “:” là gì?


80

Đây là hai chữ ký chức năng tôi đã thấy trong tài liệu Rust:

fn modify_foo(mut foo: Box<i32>) { *foo += 1; *foo }
fn modify_foo(foo: &mut i32) { *foo += 1; *foo }

Tại sao vị trí khác nhau của mut?

Có vẻ như hàm đầu tiên cũng có thể được khai báo là

fn modify_foo(foo: mut Box<i32>) { /* ... */ }

Đối với lập trình viên C ++: sự khác biệt tương tự như con trỏ constpointeeconst .
Legends2k

Câu trả lời:


87

mut foo: Tnghĩa là bạn có một biến được gọi foolà a T. Bạn được phép thay đổi những gì biến đề cập đến :

let mut val1 = 2;
val1 = 3; // OK

let val2 = 2;
val2 = 3; // error: re-assignment of immutable variable

Điều này cũng cho phép bạn sửa đổi các trường của cấu trúc mà bạn sở hữu:

struct Monster { health: u8 }

let mut orc = Monster { health: 93 };
orc.health -= 54;

let goblin = Monster { health: 28 };
goblin.health += 10; // error: cannot assign to immutable field

foo: &mut Tnghĩa là bạn có một biến tham chiếu đến ( &) một giá trị và bạn được phép thay đổi ( mut) giá trị được tham chiếu (bao gồm các trường, nếu đó là một cấu trúc):

let val1 = &mut 2;
*val1 = 3; // OK

let val2 = &2;
*val2 = 3; // error: cannot assign to immutable borrowed content

Lưu ý rằng &mutchỉ có ý nghĩa với một tham chiếu - foo: mut Tkhông phải là cú pháp hợp lệ. Bạn cũng có thể kết hợp hai định nghĩa ( let mut a: &mut T), khi nó hợp lý.


12
Tôi hiểu rồi. Tôi đoán nó giống như trong C ++, nơi bạn có thể có int const*int *constđạt được những điều khác nhau.
Jimmy Lu

3
@Shepmaster Bạn có thể muốn thêm điều đó mutvào một ràng buộc cho phép bạn thay đổi bên trong cấu trúc (nếu đó là một cấu trúc).
Scott Olson

7
@BeyondSora Đừng nghĩ &mut Type&(mut Type), mà là (&mut) Type. Từ khóa mutnói chung không được sử dụng trong các loại, nhưng có một loại tham chiếu được gọi là &mut.
Scott Olson

2
@BeyondSora Bạn có thể xem bản chỉnh sửa mới nhất của câu trả lời ở trên. Lời giải thích cơ bản là khi bạn có thể thay đổi một cấu trúc, bạn có thể thay đổi cấu trúc đến mức bạn muốn (các trường của nó, các trường của nó, v.v.). Không có constlĩnh vực nào . Điều này là an toàn vì Rust đảm bảo khi bạn có thể biến đổi thứ gì đó, không ai khác có thể đọc hoặc biến đổi nó cùng một lúc.
Scott Olson

2
@didierc Vâng. Bạn có thể nghĩ về &T&mut Tnhư là đường cho Ref<T>RefMut<T>(loại mà tôi vừa tạo ra).
Scott Olson

93

Nếu bạn đến từ C / C ++, cũng có thể hữu ích khi nghĩ về nó cơ bản như thế này:

// Rust          C/C++
    a: &T     == const T* const a; // can't mutate either
mut a: &T     == const T* a;       // can't mutate what is pointed to
    a: &mut T == T* const a;       // can't mutate pointer
mut a: &mut T == T* a;             // can mutate both

Bạn sẽ nhận thấy rằng đây là những nghịch đảo của nhau. C / C ++ sử dụng cách tiếp cận "danh sách đen", trong đó nếu bạn muốn điều gì đó là bất biến, bạn phải nói rõ ràng như vậy, trong khi Rust thực hiện cách tiếp cận "danh sách trắng", trong đó nếu bạn muốn điều gì đó có thể thay đổi, bạn phải nói rõ ràng như vậy.


3
Đây là một bàn tuyệt vời. Có thể cần lưu ý rằng các &mut Ttham chiếu cũng tương tự như các T* restrictcon trỏ trong C: chúng có thể không có bí danh. &Ttham chiếu không có ràng buộc như vậy và không có kiểu tham chiếu tương tự như con trỏ không restrictđủ tiêu chuẩn T*.
trentcl

1
Tôi không có nền tảng C, nhưng tôi vẫn nghĩ điều này giải thích nó tốt hơn (với các nhận xét) trái ngược với câu trả lời được chấp nhận, đôi khi đơn giản hơn là tốt hơn.
kres0345
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.