2014-10-19 14 views
6

Các Rust Guide bang rằng:Việc thêm dấu chấm phẩy vào cuối `trả lại` có tạo sự khác biệt không?

The semicolon turns any expression into a statement by throwing away its value and returning unit instead.

tôi nghĩ rằng tôi có khái niệm này xuống cho đến khi tôi chạy một thử nghiệm:

fn print_number(x: i32, y: i32) -> i32 { 
    if x + y > 20 { return x }  
    x + y 
} 

nào biên dịch tốt. Sau đó, tôi đã thêm một dấu chấm phẩy ở cuối dòng trả về (return x;). Từ những gì tôi hiểu, điều này biến dòng thành một tuyên bố, trả về đơn vị loại dữ liệu ().

Tuy nhiên, kết quả cuối cùng cũng giống nhau.

Trả lời

2

Tôi không chắc chắn 100% những gì tôi đang nói nhưng điều đó có ý nghĩa.

Có một khái niệm khác sắp phát hành: phân tích khả năng hiển thị. Trình biên dịch biết rằng những gì theo sau câu lệnh biểu hiện return là không thể truy cập được. Ví dụ, nếu chúng ta biên dịch chức năng này:

fn test() -> i32 { 
    return 1; 
    2 
} 

Chúng tôi nhận được cảnh báo sau đây:

warning: unreachable expression 
--> src/main.rs:3:5 
    | 
3 |  2 
    | ^
    | 

Trình biên dịch có thể bỏ qua "true" chi nhánh của biểu thức if nếu nó kết thúc với một biểu thức return và chỉ xem xét nhánh "sai" khi xác định loại biểu thức if.

Bạn cũng có thể xem hành vi này với diverging functions. Chức năng phân phối là các hàm không trả về bình thường (ví dụ: chúng luôn thất bại). Thử thay thế biểu thức return bằng macro fail! (mở rộng đến cuộc gọi đến chức năng phân tách). Thực tế, các biểu thức return cũng được coi là phân tách; đây là cơ sở của phân tích khả năng tiếp cận nói trên.

Tuy nhiên, nếu có biểu thức () thực tế sau tuyên bố return, bạn sẽ gặp lỗi. Chức năng này:

fn print_number(x: i32, y: i32) -> i32 { 
    if x + y > 20 { 
     return x; 
     () 
    } else { 
     x + y 
    } 
} 

cung cấp cho các lỗi sau:

error[E0308]: mismatched types 
--> src/main.rs:4:9 
    | 
4 |  () 
    |   ^^ expected i32, found() 
    | 
    = note: expected type `i32` 
      found type `()` 

Cuối cùng, có vẻ như phân kỳ biểu thức (trong đó bao gồm return biểu thức) được xử lý khác nhau bởi trình biên dịch khi chúng được theo sau bởi một dấu chấm phẩy: tuyên bố vẫn đang phân tách.

+0

Cách khác nhau? bạn có khác biệt gì khi không có dấu chấm phẩy? – sargas

+0

Không có dấu chấm phẩy, các biểu thức 'trả về' và các biểu thức phân kỳ có vẻ tương thích với bất kỳ biểu thức nào và chúng dường như giữ lại đặc điểm đặc biệt đó ngay cả khi chúng được theo sau bởi dấu chấm phẩy. –

+0

Đây chính xác là những gì họ đã nói với tôi tại kênh IRC. Về cơ bản, nó không tạo ra sự khác biệt nào cho kết quả cuối cùng (ít nhất là ví dụ của tôi), nhưng việc thêm dấu chấm phẩy có thể an tâm :) – sargas

4

Thông thường, mỗi nhánh trong biểu thức if phải có cùng loại. Nếu loại đối với một số ngành được underspecified, trình biên dịch sẽ cố gắng để tìm ra loại phổ biến duy nhất:

fn print_number(x: int, y: int) { 
    let v = if x + y > 20 { 
    3 // this can be either 3u, 3i, 3u8 etc. 
    } else { 
    x + y // this is always int 
    }; 
    println!("{}", v); 
} 

Trong mã này, 3 là underspecified nhưng else chi nhánh lực lượng nó có các loại int.

Điều này nghe có vẻ đơn giản: Có một chức năng "hợp nhất" hai hoặc nhiều loại thành loại phổ biến, hoặc nó sẽ cho bạn một lỗi khi điều đó là không thể. Nhưng nếu có một số fail! trong chi nhánh thì sao?

fn print_number(x: int, y: int) { 
    let v = if x + y > 20 { 
    fail!("x + y too large") // ??? 
    } else { 
    x + y // this is always int 
    }; 
    println!("{}", v); // uh wait, what's the type of `v`? 
} 

Tôi muốn rằng fail! không ảnh hưởng đến các chi nhánh khác, đó là trường hợp ngoại lệ. Vì mẫu này khá phổ biến trong Rust, khái niệm về loại phân tách đã được giới thiệu. Không có giá trị mà loại nào đang phân tách. (Nó cũng được gọi là "loại không có người ở" hoặc "loại trống" tùy thuộc vào ngữ cảnh. Không được nhầm lẫn với "loại đơn vị" có giá trị đơn là ().) Vì loại phân tách tự nhiên là tập hợp con của bất kỳ loại nào khác các loại, trình biên dịch kết luận rằng loại của v chỉ là loại của chi nhánh else, int.

Return biểu thức không khác với fail! nhằm mục đích kiểm tra loại. Nó đột ngột thoát khỏi luồng thực hiện hiện tại giống như fail! (nhưng không chấm dứt tác vụ, may mắn). Tuy nhiên, các loại phân kỳ không tuyên truyền để báo cáo kết quả tiếp theo:

fn print_number(x: int, y: int) { 
    let v = if x + y > 20 { 
    return; // this is diverging 
    () // this is implied, even when you omit it 
    } else { 
    x + y // this is always int 
    }; 
    println!("{}", v); // again, what's the type of `v`? 
} 

Lưu ý rằng semicoloned tuyên bố duy nhất x; tương đương với biểu thức x;(). Thông thường a; b có cùng loại với b, vì vậy sẽ khá lạ khi x;() có loại ()chỉ khix không phân kỳ và nó phân kỳ khi x phân kỳ. Đó là lý do tại sao mã ban đầu của bạn không hoạt động.

Nó là hấp dẫn để thêm một trường hợp đặc biệt như thế:

  • Tại sao bạn không làm cho x;() phân kỳ khi x phân kì?
  • Tại sao bạn không giả sử uint cho mỗi số nguyên không xác định bằng chữ khi loại của nó không thể suy ra? (Lưu ý: đây là trường hợp trong quá khứ.)
  • Tại sao bạn không tự động tìm thấy siêu eo biển chung khi hợp nhất nhiều đối tượng đặc điểm?

Sự thật là, thiết kế hệ thống kiểu không khó, nhưng việc xác minh hệ thống khó hơn và chúng tôi muốn đảm bảo rằng hệ thống kiểu của Rust tương thích và lâu dài. Một số người trong số họ có thể xảy ra nếu nó thực sự hữu ích và nó được chứng minh là "đúng" cho mục đích của chúng tôi, nhưng không phải ngay lập tức.

+0

Tôi cảm thấy như tôi hiểu thêm về cách 'return',' fail! ', Và * Diverging Chức năng * hoạt động. Ví dụ mã của tôi biên dịch bất kể sự hiện diện của dấu chấm phẩy tại 'return x'. Vì vậy, tôi đoán rằng dòng dưới cùng là: thêm nó sẽ không tạo ra sự khác biệt? – sargas

+0

Tôi đã chỉnh sửa ví dụ về mã của mình để làm rõ câu hỏi của mình hơn một chút. Tuy nhiên, 'return x' và' return x; 'dường như đã làm điều tương tự ở cuối và tôi không biết sự khác biệt của nó khi sử dụng dấu chấm phẩy trong trường hợp này. Bản chỉnh sửa của tôi có thay đổi ngữ cảnh cho câu hỏi của bạn không? (Vẫn cố hiểu những khái niệm cấp thấp của Rust). – sargas

+1

@sargas: Chỉnh sửa của bạn hoàn toàn thay đổi tình huống. Trước đó, đuôi của hàm là biểu thức 'if'; bây giờ, đuôi của hàm là biểu thức 'x + y'. Trong cả hai trường hợp, biểu thức 'return' có thể gây ra một lối thoát sớm.Tuy nhiên, trong mẫu đã chỉnh sửa của bạn, loại biểu thức 'if' trở nên không liên quan (và chúng ta biết đó là'() 'bởi vì nó không có mệnh đề' else', chỉ được phép nếu mệnh đề 'if' ước lượng '()'). Điều đó nói rằng, cá nhân, nếu tôi kết thúc một 'if' với một' return', tôi không viết một 'else' và thay vào đó đặt mã đó ngay sau' if', như bạn đã làm trong bản chỉnh sửa của mình. –

Các vấn đề liên quan