Scala 在方法到方法调用中找不到隐式值
我试图通过使用Scala 在方法到方法调用中找不到隐式值,scala,Scala,我试图通过使用implicit类和类型类向配置库添加一个helper方法。但是,我对Scala非常陌生(1周),无法找出以下代码出现编译错误的原因(我在代码中的注释中提供了有效的解决方案) 简化第三方程序包: package pkg class Config { def hasPath(path: String) = { false } def getString(path: String) = { "str" } def getInt(path: String) = { 7 }
implicit
类和类型类向配置库添加一个helper方法。但是,我对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}")
}
此代码给出错误无法找到参数提取器的隐式值:Helpers.extractor[T]
为什么从extract(path,默认值)
中调用extract(path)
时找不到隐式值?我对范围规则的理解或解决隐式问题的理解是错误的。我本以为,当从extract(path,default)
中调用extract(path)
时,仍然可以从Extractor
的伴生对象解析隐式
我在Scala 2.10.6和2.11.8中尝试过这一点。您的调用需要一个隐式的
提取器[T]
,其中对T
一无所知。如果有伴星的话,它可以从伴星上解析出来,但是那里没有这样的方法
想象一下它起作用了。然后
val cfg = new Config
val x = cfg.extract[String]("foo", "")
也应该编译。但是,如果没有隐式的
提取器[String]
的话,它将如何工作呢?编译器在什么时候尝试计算出T是什么?我猜我错误地认为它会知道T是Int,因为这是整型文字“3”的类型。我完全可以看出字符串版本不起作用,因为我没有提供提取器[String]的实现(至少在本例中是这样)。当编译器查看def extract[T](路径:String,默认值:T):T
,它根本不试图找出t
是什么:您的定义必须适用于所有t
。当查看cfg.extract(“foo”,3)
时,它发现t
对于这个特定调用是Int
,但这是分开的;你已经在定义中有一个错误了,即使你从来没有调用过这个方法。啊!好啊我一直在阅读的教程等并没有真正解释编译器何时处理泛型类型。我有C++背景,并且在编译器使用泛型函数(模板)时,它实际上只用于尝试解析相关函数调用。我从代码中删除了cfg.extract(“foo”,3)
调用,正如您所说,它不会编译。现在我明白发生了什么,谢谢!