2012-11-22 18 views
16

Đây là chương trình để tìm ra thừa của một số trong Go:Go mã không biên dịch mà không có một lệnh return unreachable

func factorial(x uint) uint { 
    if x == 0 { 
     return 1 
    } 

    return x * (factorial(x - 1)) 
} 

Kết quả cho chức năng này khi kêu gọi đầu vào 5 là 120. Tuy nhiên, nếu tôi thêm tuyên bố else tôi sẽ gặp lỗi.

func factorial(x uint) uint { 
    if x == 0 { 
     return 1 
    } else { 
     return x * (factorial(x - 1)) 
    } 
} 

Lỗi: function ends without a return statement

Tôi đã thêm một return ở cuối:

func factorial(x uint) uint { 
    if x == 0 { 
     return 1 
    } else { 
     return x * (factorial(x - 1)) 
    } 
    fmt.Println("this never executes") 
    return 1 
} 

và tôi lấy lại kết quả mong muốn của 120.

Tại sao trường hợp thứ hai sẽ gây ra một lỗi? Tại sao trong trường hợp thứ ba mặc dù chức năng không bao giờ đạt đến cuối cùng return 1, nó tính toán đầu ra chính xác?

+1

Đó là thành ngữ trong Đi tới để sử dụng 'if cond {return}; return' (không phải trên một dòng rõ ràng). Khi bạn có vô tận cho các vòng lặp bất cứ nơi nào sau khi vòng lặp không thực thi, thành ngữ phổ biến là thêm 'hoảng loạn (" không thể truy cập ")'. –

+0

làm cho câu lệnh cuối cùng là 'hoảng loạn (" không bao giờ đạt được ")' – thwd

Trả lời

22

Đây là vấn đề nổi tiếng của trình biên dịch.

Thậm chí còn có một vấn đề đăng nhập: http://code.google.com/p/go/issues/detail?id=65

Theo lời của một trong những tác giả của ngôn ngữ Go:

Các trình biên dịch đòi hỏi hoặc trả lại hàng hoặc một hoảng loạn để được giải nghĩa từ vựng qua trong một hàm có kết quả. Quy tắc này dễ hơn yêu cầu phân tích kiểm soát luồng đầy đủ để xác định xem hàm có đạt đến kết thúc mà không trả lại (thường rất khó) và đơn giản hơn quy tắc liệt kê các trường hợp dễ dàng như trường hợp này. Ngoài ra, hoàn toàn là từ vựng, lỗi không thể phát sinh một cách tự phát do thay đổi về giá trị chẳng hạn như hằng số được sử dụng trong cấu trúc điều khiển bên trong hàm.

-rob

Từ một bình luận in golang-nuts, chúng ta có thể suy ra nó sẽ không được "cố định" sớm:

Đó không phải là lỗi, đó là một quyết định thiết kế có chủ ý.

-rob

Lưu ý rằng các ngôn ngữ khác như Java có những quy định cho phép else này.


tháng 3 năm 2013 EDIT - Nó chỉ got changed in Go1.1:

Trước Go 1.1, một chức năng đó quay trở lại một giá trị cần một rõ ràng "trở lại" hoặc gọi đến hoảng loạn vào cuối của hàm ; đây là một cách đơn giản để làm cho lập trình viên hiểu rõ ý nghĩa của hàm . Nhưng có rất nhiều trường hợp khi "trả lại" cuối cùng rõ ràng là không cần thiết, chẳng hạn như một hàm chỉ có vòng lặp "for" vô hạn.

Trong bước 1.1, quy tắc về câu trả lời "trả lại" cuối cùng là nhiều hơn cho phép. Nó giới thiệu khái niệm về một câu lệnh kết thúc, một câu lệnh được đảm bảo là câu lệnh cuối cùng mà một hàm thực thi. Ví dụ bao gồm các vòng "cho" không có điều kiện và các câu lệnh "if-else" trong đó mỗi nửa kết thúc bằng "trả lại". Nếu câu lệnh cuối cùng của hàm có thể được hiển thị theo cú pháp để kết thúc câu lệnh , thì không cần câu lệnh "trả lại" cuối cùng.

Lưu ý rằng quy tắc hoàn toàn là cú pháp: nó không chú ý đến các giá trị trong mã và do đó không yêu cầu phân tích phức tạp.

Cập nhật: Thay đổi tương thích ngược, nhưng mã hiện tại với các câu lệnh "return" không cần thiết có thể được đơn giản hóa theo cách thủ công. Mã như vậy có thể được xác định bởi go vet.

Và vấn đề tôi đã đề cập hiện đã bị đóng với trạng thái "Cố định".

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