Tại sao Rust cho phép mã với kiểu trả về sai, nhưng chỉ với dấu chấm phẩy?


8

Hãy xem xét mã Rust sau đây:

fn f() -> i32 {
    loop {
        println!("Infinite loop!");
    }
    println!("Unreachable");
}

Điều này biên dịch (với một cảnh báo) và chạy, mặc dù thực tế là loại trả lại là sai. Có vẻ như trình biên dịch vẫn ổn với kiểu trả về của ()dòng cuối cùng vì nó phát hiện ra rằng mã này không thể truy cập được.

Tuy nhiên, nếu chúng ta xóa dấu chấm phẩy cuối cùng:

fn f() -> i32 {
    loop {
        println!("Infinite loop!");
    }
    println!("Unreachable")
}

Sau đó, mã không còn biên dịch, đưa ra một lỗi loại:

error[E0308]: mismatched types
  --> src/main.rs:14:5
   |
14 |     println!("Unreachable")
   |     ^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `()`
   |
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

Tại sao lại thế này? Không phải kiểu trả về giống nhau (), trong cả hai đoạn mã này?


Lưu ý: Tôi muốn tìm hiểu lý do tại sao trình biên dịch Rust hoạt động khác nhau trên hai ví dụ này, tức là cách trình biên dịch Rust được triển khai. Tôi không có ý hỏi một câu hỏi triết học về cách nó "nên" hành xử, từ quan điểm của thiết kế ngôn ngữ (tôi hiểu rằng một câu hỏi như vậy có thể sẽ lạc đề).


1
Trình biên dịch Rust cần suy ra một kiểu cho thân hàm. Trong trường hợp đầu tiên, không có biểu thức trả về và rõ ràng trình biên dịch sẽ !là kiểu trả về vì vòng lặp vô hạn, điều này có ý nghĩa. Trong trường hợp thứ hai, có một biểu thức trả về, do đó, bộ giải suy luận kiểu sử dụng nó để suy ra kiểu, điều này cũng có ý nghĩa. Tôi không nghĩ rằng điều này được chỉ định trong tài liệu tham khảo ngôn ngữ, tôi cũng không nghĩ nó quan trọng theo bất kỳ cách nào - chỉ cần bỏ qua tuyên bố không thể truy cập và bạn sẽ ổn.
Sven Marnach

@SvenMarnach Vẫn là một câu hỏi về ngôn ngữ. Tôi nghĩ rằng đó vẫn là chủ đề.
Hội trường Peter

1
@SvenMarnach Điều đó có thực sự cần thiết? Tôi chưa quen với Rust và tôi đang cố gắng hiểu tại sao trình biên dịch lại làm những gì nó làm. Tôi không yêu cầu bất kỳ câu trả lời triết học. Tôi nghĩ rằng ý kiến ​​của bạn cho thấy một số hiểu lầm về câu hỏi của tôi và góp phần vào nhận thức rằng SO là độc hại.
6005

@ 6005 Nhận xét của Sven hoàn toàn không liên quan đến "văn hóa độc hại" mà SO đã bị buộc tội (trừ khi bạn thực sự nghĩ rằng anh ta đối xử với bạn khác biệt vì giới tính, giới tính, chủng tộc, v.v.). Ông đã đóng góp cho một cuộc thảo luận (văn minh) về việc câu hỏi của bạn có phù hợp với SO hay không.
Hội trường Peter

3
Có lẽ tôi hơi ngắn gọn, nhưng tôi chắc chắn không có ý xúc phạm. Tôi không nghĩ có gì sai với câu hỏi của bạn - tôi thậm chí rất thích nó. :) Tôi chỉ không nghĩ rằng có bất kỳ câu trả lời "đúng" nào cho nó, vì các chi tiết về suy luận kiểu trong Rust không được chỉ định. Chúng ta có thể thấy kiểu suy luận nào trong trường hợp này, nhưng đơn giản là không có lý do nào sâu sắc hơn cho nó. Có lẽ ai đó có kiến ​​thức sâu sắc về nội bộ trình biên dịch có thể giải thích lý do tại sao trình biên dịch hành xử theo cách này, nhưng chúng tôi sẽ không tìm hiểu nhiều về ngôn ngữ.
Sven Marnach

Câu trả lời:


6

Kiểu trả về trong khối mã đầu tiên thực sự !(được gọi là không bao giờ) bởi vì bạn có một vòng lặp không bao giờ thoát (do đó rỉ sét đưa ra cảnh báo cho biết nó không thể truy cập được). Loại đầy đủ sẽ là:

fn f() -> !

Tôi nghi ngờ !giống kiểu 'đáy' trong Rust hơn bất cứ thứ gì khác. Trong trường hợp thứ hai, hàm của bạn có khả năng bị lỗi ở giai đoạn sớm hơn trong quá trình kiểm tra kiểu do sự không khớp giữa i32 và () trước khi trình biên dịch chuyển sang phân tích 'không thể truy cập', giống như trong ví dụ đầu tiên.

chỉnh sửa: như được đề xuất, đây là phần có liên quan của cuốn sách rỉ sét https://doc.rust-lang.org/book/ch19-04-advified-types.html#the-never-type-that-never-returns


1
Nó có thể giúp liên kết đến phần về nó trong cuốn sách Rust. Cụ thể, nó nói: "Cách chính thức để mô tả hành vi này là các biểu thức của loại !có thể bị ép buộc thành bất kỳ loại nào khác. "
Herohtar

Cảm ơn! Điều đó thật thú vị, tôi sẽ đọc vào đây. Tuy nhiên, cảnh báo không liên quan đến rằng: cảnh báo chỉ là "tuyên bố không thể truy cập" (trỏ đến cuối cùng println!)
6005

Đó chính xác là những gì tôi đã ám chỉ. Tuyên bố là không thể truy cập, và loại trả lại của bạn là!
Được khuyến nghị

Cảm ơn câu trả lời của bạn, tôi hy vọng nó là chính xác và tôi không chấp nhận một lời giải thích sai :)
6005

Đúng rồi, hãy đọc liên kết
vào

0

(Chuyển nhận xét đầu tiên của Sven thành câu trả lời)

Trình biên dịch Rust cần suy ra một kiểu cho thân hàm. Trong trường hợp đầu tiên, không có biểu thức trả về, và rõ ràng trình biên dịch sẽ xâm nhập! như kiểu trả về vì vòng lặp vô hạn, có ý nghĩa. Trong trường hợp thứ hai, có một biểu thức trả về, do đó, bộ giải suy luận kiểu sử dụng nó để suy ra kiểu, điều này cũng có ý nghĩa.

Tôi không nghĩ rằng điều này được chỉ định trong tài liệu tham khảo ngôn ngữ, tôi cũng không nghĩ nó quan trọng theo bất kỳ cách nào - chỉ cần bỏ qua tuyên bố không thể truy cập và bạn sẽ ổn.

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.