2016-11-13 119 views
4
trait Encoder[From, To] { 
    def encode(x: From): To 
} 
object Encoder { 
    implicit val thingToString: Encoder[Thing, String] = new Encoder[Thing, String] { 
    def encode(x: Thing): String = x.toString 
    } 
} 

trait Config { 
    type Repr 
} 
class MyConfig extends Config { type Repr = String } 
//class ConcreteConfig { type Repr = String } 

class Api[T](val config: Config) { 
    def doSomething(value: T)(implicit encoder: Encoder[T, config.Repr]): Unit = {} 
} 

case class Thing(a: Int) 

object Test extends App { 
    import Encoder._ 

    val api = new Api[Thing](new MyConfig) 
    api.doSomething(Thing(42)) 
} 

api.doSomething調用失敗編譯:斯卡拉:類型類實例的隱式的查找路徑依賴型

could not find implicit value for parameter encoder: Encoder[Thing,Test.api.config.Repr] 

如果我改變class Api[T]的構造方法的簽名,這樣只有一個ConcreteConfig ,那麼編譯器可以知道config.Repr == String和隱式查找成功。但是這對我的用例並不適用。

是否有任何其他方式來指導隱式查找?我是否因爲缺少類型優化或某種東西而丟失了類型信息?

回答

0

由於config.Repr不是一個穩定的路徑,因此無法實現。儘管config的運行時值是MyConfig類型,但編譯器無法確定config.Repr = String。

這將只工作,如果你能提供具體的配置實例作爲阿比類型參數,它會告訴編譯器什麼的確切類型REPR的:

class Api[T, C <: Config](val config: C) { 
    def doSomething(value: T)(implicit encoder: Encoder[T, config.Repr]): Unit = {} 
} 

object Test extends App { 
    import Encoder._ 

    val api = new Api[Thing, MyConfig](new MyConfig) 
    api.doSomething(Thing(42)) 
} 
+0

'api.config.Repr' _is_一個穩定的路徑,雖然你的第二句話是正確的。 –

0

推斷類型一步一個時間。此外,我沒有看到在這裏使用依賴於值的類型的任何理由(或者對於那個地方,儘管這是一個不同的問題)。

trait Encoder[From, To] { 
    def encode(x: From): To 
} 
object Encoder { 

    implicit val thingToString: Encoder[Thing, String] = new Encoder[Thing, String] { 
    def encode(x: Thing): String = x.toString 
    } 
} 

trait Config { 
    type Repr 
} 
class MyConfig extends Config { type Repr = String } 
// class ConcreteConfig { type Repr = String } 

case class Api[T, C <: Config](val config: C) { 
    def doSomething(value: T)(implicit encoder: Encoder[T, C#Repr]): Unit =() 
} 

case class ApiFor[T]() { 
    def withConfig[C <: Config](config: C): Api[T,C] = Api(config) 
} 

case class Thing(a: Int) 

object Test extends App { 
    import Encoder._ 

    val api = ApiFor[Thing] withConfig new MyConfig 
    // compiles! 
    api.doSomething(Thing(42)) 
}