2016-09-15 44 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'用於這個特定的調用,但是這是獨立的;即使你從來沒有調用過這個方法,你在定義中已經有了一個錯誤。 –

相關問題