2010-06-27 33 views
11

Trình biên dịch Scala thường có thể suy ra các kiểu trả về cho các phương thức, nhưng có một số trường hợp cần phải xác định kiểu trả về. Ví dụ, các phương thức đệ quy yêu cầu một kiểu trả về được xác định. Tôi nhận thấy rằng đôi khi tôi nhận được thông báo lỗi "phương thức quá tải (tên phương thức) yêu cầu kiểu trả về", nhưng nó không phải là một quy tắc chung mà các kiểu trả về luôn phải được chỉ định cho các phương thức quá tải (tôi có các ví dụ mà tôi không nhận được) lỗi này).Khi nào là kiểu trả về được yêu cầu cho các phương thức trong Scala?

Khi nào thì bắt buộc phải xác định loại trả lại, cho các phương pháp nói chung và cụ thể cho các phương thức quá tải?

+4

Như một vấn đề của (phong cách cá nhân của tôi), tôi cung cấp cho các loại lợi nhuận rõ ràng cho tất cả nhưng những phương pháp đơn giản nhất (về cơ bản, một lớp lót với không có logic có điều kiện). Hãy nhớ rằng nếu bạn để trình biên dịch suy ra loại kết quả của phương thức, nó có thể cụ thể hơn bạn muốn. (Ví dụ: 'HashMap' thay vì' Bản đồ'.) –

+0

@Randall có, điểm tốt (về kiểu trả về quá cụ thể). – Jesper

Trả lời

18

Các Chapter 2. Type Less, Do More của cuốn sách Programming Scala đề cập:

Khi Loại chú thích rõ ràng được yêu cầu.

Trên thực tế, bạn phải cung cấp chú thích kiểu tường minh trong các trường hợp sau đây:

giá trị Phương pháp trở lại trong các trường hợp sau:

  • Khi bạn một cách rõ ràng gọi trở lại trong một phương pháp (ngay cả ở kết thúc).
  • Khi phương pháp đệ quy.
  • Khi phương thức bị quá tải và một trong các phương pháp gọi một phương thức khác. Phương thức gọi cần chú thích kiểu trả về.
  • Khi loại trả về phỏng đoán sẽ tổng quát hơn bạn dự định, ví dụ: Any.

Ví dụ:

// code-examples/TypeLessDoMore/method-nested-return-script.scala 
// ERROR: Won't compile until you put a String return type on upCase. 

def upCase(s: String) = { 
    if (s.length == 0) 
    return s // ERROR - forces return type of upCase to be declared. 
    else 
    s.toUpperCase() 
} 

phương pháp quá tải đôi khi có thể đòi hỏi một kiểu trả về rõ ràng. Khi một phương thức như vậy gọi một phương thức khác, chúng ta phải thêm kiểu trả về cho một phương thức thực hiện cuộc gọi, như trong ví dụ này.

// code-examples/TypeLessDoMore/method-overloaded-return-script.scala 
// Version 1 of "StringUtil" (with a compilation error). 
// ERROR: Won't compile: needs a String return type on the second "joiner". 

object StringUtil { 
    def joiner(strings: List[String], separator: String): String = 
    strings.mkString(separator) 

    def joiner(strings: List[String]) = joiner(strings, " ") // ERROR 
} 
import StringUtil._ // Import the joiner methods. 

println(joiner(List("Programming", "Scala"))) 

Hai joiner phương pháp nối một List các chuỗi lại với nhau.
Phương pháp đầu tiên cũng lấy một đối số cho chuỗi dấu phân tách.
Phương pháp thứ hai gọi phương thức đầu tiên với dấu phân cách “mặc định” của một dấu cách.

Nếu bạn chạy tập lệnh này, bạn sẽ gặp phải lỗi sau.

... 9: error: overloaded method joiner needs result type 
def joiner(strings: List[String]) = joiner(strings, "") 

Kể từ thứ hai phương pháp joiner gọi đầu tiên, nó đòi hỏi một kiểu tường minh String trở lại.Nó sẽ giống như thế này:

def joiner(strings: List[String]): String = joiner(strings, " ") 

Về cơ bản, xác định kiểu trả về có thể là một thực hành tốt mặc dù Scala có thể suy ra nó.


Randall Schulz nhận xét:

Như một vấn đề của phong cách (cá nhân tôi), tôi cung cấp cho các loại lợi nhuận rõ ràng cho tất cả nhưng những phương pháp đơn giản nhất (về cơ bản, một lớp lót với không có logic có điều kiện).

Hãy nhớ rằng nếu bạn để trình biên dịch suy ra loại kết quả của phương thức, nó có thể cụ thể hơn bạn muốn. (Ví dụ: HashMap thay vì bản đồ.)

Và kể từ khi bạn có thể muốn để lộ giao diện tối thiểu trong kiểu trả về của bạn (xem ví dụ SO question này), loại suy luận có thể nhận được trong cách.


Và về kịch bản cuối cùng ("Khi kiểu trả về suy ra sẽ là tổng quát hơn hơn bạn dự định"), Ken Bloom cho biết thêm:

xác định kiểu trả về khi bạn muốn trình biên dịch để xác minh mã trong hàm trả về loại bạn mong đợi

(Mã lỗi kích hoạt "loại trả về chung hơn mong đợi là:

// code-examples/TypeLessDoMore/method-broad-inference-return-script.scala 
// ERROR: Won't compile. Method actually returns List[Any], which is too "broad". 

def makeList(strings: String*) = { 
    if (strings.length == 0) 
    List(0) // #1 
    else 
    strings.toList 
} 

val list: List[String] = makeList() // ERROR 

, mà tôi không đúng cách giải thích và Danh sách [Bất kỳ] vì trả lại một Danh sách trống rỗng, nhưng Ken gọi nó ra:

List(0) không tạo ra một danh sách với 0 tố.
Nó tạo ra một List[Int] chứa một phần tử (giá trị 0).
Do đó, List[Int] trên một nhánh có điều kiện và List[String] trên nhánh có điều kiện khác tổng quát thành List[Any].
Trong trường hợp này, typer không quá chung chung - đó là lỗi trong mã.
)

+0

"Khi loại trả về phỏng đoán sẽ tổng quát hơn bạn dự định, ví dụ: Bất kỳ". Điều này thật kỳ lạ. Trên thực tế, tôi sẽ xem xét rằng một lỗi trong Typer. Tôi chưa bao giờ trải qua một cái gì đó như thế. Bạn có một ví dụ? – soc

+0

@soc: http://programming-scala.labs.oreilly.com/ch02.html không có một ví dụ khi trả về một 'List (0)' ('List' của size 0) sẽ trả về và' List [Any] 'thay vì' List [String] 'trừ khi bạn chỉ định kiểu trả về. – VonC

+2

'Danh sách (0)' không tạo danh sách có 0 phần tử. Nó tạo ra một 'List [Int]' chứa một phần tử (giá trị '0'). Do đó một 'List [Int]' trên một nhánh có điều kiện và một 'List [String]' trên nhánh khác có điều kiện tổng quát hóa thành 'List [Any]'. Trong trường hợp này, các typer không phải là quá chung chung - đó là một lỗi trong mã. Điều này thêm một quy tắc khác để chỉ định các kiểu trả về: ** chỉ định kiểu trả về khi bạn muốn trình biên dịch xác minh rằng mã trong hàm trả về kiểu bạn mong đợi. ** –

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