2017-05-31 22 views
5

(Scala 2.11.8)Scala typeclasses độ phân giải ngầm

Xét đoạn mã sau:

object ScalaTest extends App { 
    class Wrapper { 
    import Wrapper._ 

    def init(): Unit = { 
     // "could not find implicit value for parameter tc: ScalaTest.Wrapper.TC[Int]" 
     printWithTC(123) 

     // Compiles 
     printWithTC(123)(IntTC) 

     // Compiles again! 
     printWithTC(132) 
    } 
    } 

    object Wrapper { 
    trait TC[A] { 
     def text(a: A): String 
    } 

    implicit object IntTC extends TC[Int] { 
     override def text(a: Int) = s"int($a)" 
    } 

    def printWithTC[A](a: A)(implicit tc: TC[A]): Unit = { 
     println(tc.text(a)) 
    } 
    } 

    (new Wrapper).init() 
} 

tôi có một loạt các câu hỏi liên quan đến đoạn mã này:

  1. Tại sao doesn' t IntTC được giải quyết ngay từ đầu?
  2. Tại sao nó biên dịch sau khi được sử dụng một lần? (Nếu bạn nhận xét ra lời gọi thứ nhất, mã hoạt động)
  3. đâu typeclass implicits nên được đặt để có được giải quyết đúng cách?
+3

Tôi không có ý tưởng những gì đang xảy ra, nhưng chỉ cần để ý, rằng nếu bạn di chuyển các đối tượng được trước khi đến lớp, mã cũng biên dịch. – Dima

Trả lời

3

Sử dụng val với loại trả về rõ ràng. Xem https://github.com/scala/bug/issues/801https://github.com/scala/bug/issues/8697 (trong số những người khác).
Các đối tượng tiềm ẩn có cùng vấn đề như vals ngầm định và defs với các kiểu trả về được suy ra. Đối với câu hỏi thứ hai của bạn: khi IntTC được sử dụng một cách rõ ràng, bạn buộc trình biên dịch đánh máy nó, vì vậy sau thời điểm đó, kiểu của nó được biết và có thể được tìm thấy bằng tìm kiếm ngầm định.

class Wrapper { 
    import Wrapper._ 

    def init(): Unit = { 
    // Compiles 
    printWithTC(123) 

    // Compiles 
    printWithTC(123)(IntTC) 

    // Compiles 
    printWithTC(132) 
    } 
} 

object Wrapper { 
    trait TC[A] { 
    def text(a: A): String 
    } 

    implicit val IntTC: TC[Int] = new TC[Int] { 
    override def text(a: Int) = s"int($a)" 
    } 

    def printWithTC[A](a: A)(implicit tc: TC[A]): Unit = { 
    println(tc.text(a)) 
    } 
} 

Nếu bạn thực sự muốn tiềm ẩn của bạn được đánh giá một cách lười biếng như một đối tượng, bạn có thể sử dụng một implicit lazy val với một loại rõ ràng.

0

Xác định tiềm ẩn trước khi sử dụng nó.

object Wrapper { 
    trait TC[A] { 
    def text(a: A): String 
    } 

    implicit object IntTC extends TC[Int] { 
    override def text(a: Int) = s"int($a)" 
    } 

    def printWithTC[A](a: A)(implicit tc: TC[A]): Unit = { 
    println(tc.text(a)) 
    } 
} 

class Wrapper { 
    import Wrapper._ 

    def init(): Unit = { 
    // "could not find implicit value for parameter tc: ScalaTest.Wrapper.TC[Int]" 

    printWithTC(123) 

    // Compiles 
    printWithTC(123)(IntTC) 

    // Compiles again! 
    printWithTC(132) 
    } 
} 

(new Wrapper).init() 
+0

Chúng ta không nhập toàn bộ nội dung đối tượng vào phạm vi lớp như là dòng đầu tiên bên trong lớp? Ngoài ra, việc xác định đối tượng đồng hành sau lớp là điều phổ biến (ví dụ: http://docs.scala-lang.org/tutorials/tour/singleton-objects.html) để giải quyết vấn đề này –

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