2010-07-23 105 views
11

this class在斯卡拉:爲什麼Scala類型推斷在這裏失敗?

object Util { 
    class Tapper[A](tapMe: A) { 
    def tap(f: A => Unit): A = { 
     f(tapMe) 
     tapMe 
    } 

    def tap(fs: (A => Unit)*): A = { 
     fs.foreach(_(tapMe)) 
     tapMe 
    } 
    } 

    implicit def tapper[A](toTap: A): Tapper[A] = new Tapper(toTap) 
} 

現在,

"aaa".tap(_.trim) 

不能編譯,給人錯誤

error: missing parameter type for expanded function ((x$1) => x$1.trim)

爲什麼沒有類型推斷爲String?從錯誤看來,隱式轉換確實會觸發(否則錯誤將沿着「tap不是類String的成員」)。看起來轉換必須是Tapper[String],這意味着參數的類型是String => Unit(或(String => Unit)*)。

有趣的是,如果我註釋掉或者tap定義,那麼它會進行編譯。

回答

17

6.26.3 Overloading Resolution

One first determines the set of functions that is potentially applicable based on the shape of the arguments

...

If there is precisely one alternative in B, that alternative is chosen.

Otherwise, let S1, . . . , Sm be the vector of types obtained by typing each argument with an undefined expected type.

tap兩種過載是可能適用的(基於的參數「形狀」,其佔元數和類型構造功能N)。

所以類型確定收益,因爲它將:

val x = _.trim 

和失敗。

更聰明的算法可以採用每個備選方案的相應參數類型的最小上限,並將其用作預期類型。但是這種複雜性並不值得,國際海事組織。重載有很多轉角的情況,這是另一回事。

但是有可以在此情況下,使用一個小技巧,如果你真的需要接受單個參數的重載:

object Util { 
    class Tapper[A](tapMe: A) { 
    def tap(f: A => Unit): A = { 
     f(tapMe) 
     tapMe 
    } 

    def tap(f0: A => Unit, f1: A => Unit, fs: (A => Unit)*): A = { 
     (Seq(f0, f1) ++ fs).foreach(_(tapMe)) 
     tapMe 
    } 
    } 

    implicit def tapper[A](toTap: A): Tapper[A] = new Tapper(toTap) 

    "".tap(_.toString) 
    "".tap(_.toString, _.toString) 
    "".tap(_.toString, _.toString, _.toString) 
} 
+0

好主意,謝謝!我想我必須以不同的方式命名它們。 – 2010-07-23 08:54:03

+3

你很快成爲新的丹尼爾,傑森! – 2010-07-23 14:25:38

+2

@oxbow更好的是,他經常引用規範,這是一件好事。 – 2010-07-23 15:50:18

相關問題