2016-09-15 45 views
1

我试图通过使用implicit类和类型类将辅助方法添加到配置库。然而,我对Scala非常陌生(1周),并且一直无法找出为什么下面的代码发出编译错误(我在代码注释中提供了工作解决方案)在方法调用的方法中找不到隐式值

简化第三方包:

package pkg 

class Config { 
    def hasPath(path: String) = { false } 
    def getString(path: String) = { "str" } 
    def getInt(path: String) = { 7 } 
    def getDouble(path: String) = { 3.14d } 
} 

我的示例文件:

import pkg._ 

object Helpers { 

    trait Extractor[T] { 
    def extract(cfg: Config, path: String): T 
    } 

    object Extractor { 

    implicit object IntExtractor extends Extractor[Int] { 
     def extract(cfg: Config, path: String) = { 
     99 
     } 
    } 

    } 

    implicit class BetterConfig(cfg: Config) { 

    def extract[T](path: String)(implicit extractor: Extractor[T]): T = { 
     extractor.extract(cfg, path) 
    } 

    // This example works if I add the implicit parameter: 
    // (implicit extractor: Extractor[T]) 
    def extract[T](path: String, default: T): T = { 
     if (cfg.hasPath(path)) { 
     extract[T](path) 
     //  ^error here 
     } else { 
     default 
     } 
    } 
    } 
} 


object Demo extends App { 

    import Helpers._ 

    val cfg = new Config 
    val x = cfg.extract("foo", 3) 

    println(s"x: ${x}") 
} 

此代码提供了错误could not find implicit value for parameter extractor: Helpers.Extractor[T]

为什么不能IMPL从extract(path, default)内拨打电话extract(path)会发现icit值?我对范围规则或解决隐含的理解是错误的。我会认为,当extract(path)的调用是在extract(path, default)之内完成时,隐式仍然会从Extractor的伴随对象中解析出来。

我已经试过这与Scala 2.10.6和2.11.8。

回答

2

您的来电需要一个隐含的Extractor[T],关于T什么都不知道。它从伴侣对象解析出来,如果有的话,但是那里没有这样的方法。

想象一下它的工作。然后

val cfg = new Config 
val x = cfg.extract[String]("foo", "") 

也应该编译。但是,如果没有隐含的Extractor[String]任何地方它将如何工作?

+0

编译器在什么时候尝试确定T是什么?我想我错误地认为它会知道T是Int,因为那是整数字面量'3'的类型。我完全可以看到String版本不起作用,因为我没有提供Extractor [String]的实现(至少在本例中)。 – Timma

+0

当编译器正在查看'def extract [T](path:String,default:T):T'时,它并不试图弄清楚T是什么:你的定义必须适用于_all_'T '。 –

+1

在查看'cfg.extract(“foo”,3)'时,它指出'T'是'Int'用于这个特定的调用,但是这是独立的;即使你从来没有调用过这个方法,你在定义中已经有了一个错误。 –

相关问题