2010-07-23 51 views
11

Tôi có this class trong Scala:Tại sao suy luận kiểu Scala thất bại ở đây?

object Util { 
    class Tapper[A](tapMe: A) { 
    def tap(f: A => Unit): A = { 
     f(tapMe) 
     tapMe 
    } 

    def tap(fs: (A => Unit)*): A = { 
     fs.foreach(_(tapMe)) 
     tapMe 
    } 
    } 

    implicit def tapper[A](toTap: A): Tapper[A] = new Tapper(toTap) 
} 

Bây giờ,

"aaa".tap(_.trim) 

không biên dịch, đưa ra các lỗi

error: missing parameter type for expanded function ((x$1) => x$1.trim)

Tại sao không là kiểu suy luận như String? Từ lỗi có vẻ như việc chuyển đổi tiềm ẩn không kích hoạt (nếu không lỗi sẽ nằm dọc theo dòng "tap không phải là thành viên của lớp String"). Và có vẻ như chuyển đổi phải là Tapper[String], có nghĩa là loại đối số là String => Unit (hoặc (String => Unit)*).

Điều thú vị là nếu tôi nhận xét ra hoặc của tap định nghĩa, thì nó sẽ biên dịch.

Trả lời

17

6.26.3 Overloading Resolution

One first determines the set of functions that is potentially applicable based on the shape of the arguments

...

If there is precisely one alternative in B, that alternative is chosen.

Otherwise, let S1, . . . , Sm be the vector of types obtained by typing each argument with an undefined expected type.

Cả hai định nghĩa chồng cho tap là có khả năng áp dụng (dựa trên 'hình' của các đối số, chiếm các arity và loại nhà xây dựng FunctionN).

Vì vậy, số tiền thu được typer như nó làm với:

val x = _.trim 

và thất bại.

Thuật toán thông minh hơn có thể lấy giới hạn trên ít nhất của loại thông số tương ứng của từng phương án thay thế và sử dụng loại này làm loại dự kiến. Nhưng sự phức tạp này không thực sự đáng giá, IMO. Quá tải có nhiều trường hợp góc, đây là trường hợp khác.

Nhưng có một thủ thuật bạn có thể sử dụng trong trường hợp này, nếu bạn thực sự cần một quá tải mà chấp nhận một tham số duy nhất:

object Util { 
    class Tapper[A](tapMe: A) { 
    def tap(f: A => Unit): A = { 
     f(tapMe) 
     tapMe 
    } 

    def tap(f0: A => Unit, f1: A => Unit, fs: (A => Unit)*): A = { 
     (Seq(f0, f1) ++ fs).foreach(_(tapMe)) 
     tapMe 
    } 
    } 

    implicit def tapper[A](toTap: A): Tapper[A] = new Tapper(toTap) 

    "".tap(_.toString) 
    "".tap(_.toString, _.toString) 
    "".tap(_.toString, _.toString, _.toString) 
} 
+0

xuất sắc ý tưởng, cảm ơn! Tôi nghĩ rằng tôi sẽ phải đặt tên cho họ một cách khác nhau. –

+3

Bạn nhanh chóng trở thành Daniel mới, Jason! –

+2

@oxbow Thậm chí tốt hơn, ông thường trích dẫn thông số kỹ thuật, đó là một điều tốt. –

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