2013-10-09 82 views
1

我想定義和一個隱含的格式類型安全等於匹配太渴望:隱式轉換都會有一個隱含的參數

trait Formatter[T] { 
    def format(t : T) : String 
} 

implicit val StringFormatter : Formatter[String] = new Formatter[String] { def format(s: String) = s"'$s'" } 
implicit def AnyFormatter[T] : Formatter[T] = new Formatter[T] { def format(t : T) = t.toString } 

class MatcherOps[T : Formatter](t : T) { 
    def must_==(other : T) { 
    if(t != other) println(implicitly[Formatter[T]].format(other)) else println("OK") 
    } 
} 

implicit def ToMatcherOps[T : Formatter](t : T) = new MatcherOps[T](t) 

預期以下工作:

"ha" must_== "ho" 

它編譯(​​)到

$anon.this.ToMatcherOps[String]("ha")($anon.this.StringFormatter).must_==("ho"); 

但我希望它可以不編譯:

List(1,2) must_== Set(1,2) 

,而是它編譯(​​)到

$anon.this.ToMatcherOps[Object]($anon.this.ToMatcherOps[List[Int]](immutable.this.List.apply[Int](1, 2))($anon.this.AnyFormatter[List[Int]]))($anon.this.AnyFormatter[Object]).must_==(scala.this.Predef.Set.apply[Int](1, 2)) 

正如你可以看到ToMatcherOps被調用了兩次!

我若隱格式化的方式進行:

implicit def ToMatcherOps[T](t : T) = new MatcherOps[T](t) 

然後編譯如預期失敗:

error: type mismatch; 
    found : scala.collection.immutable.Set[Int] 
    required: List[Int] 
List(1,2) must_== Set(1,2) 
        ^

但當然ToMatcherOps不能提供一個合理的Formatter(​​):

implicit private def ToMatcherOps[T >: Nothing <: Any](t: T): this.MatcherOps[T] = new this.MatcherOps[T](t)($anon.this.AnyFormatter[T]); 

任何想法如何解決這個問題? 謝謝

+0

你說它的作品,如果你刪除格式化隱式,那麼問題是什麼? – Yaroslav

+0

那麼我沒有格式化。我會編輯這個問題來說明問題。 –

回答

0

這就是我想出的。將隱式格式器參數從MatherOps類移到它的方法。

package testpkg 

trait Formatter[T] { 
    def format(x: T): String 
} 

class MatcherOps[T](x : T) { 
    def must_==(y: T)(implicit z: Formatter[T]) { 
    if(x != y) 
     println(z.format(y)) 
    else 
     println("OK") 
    } 
} 

object Test { 
    implicit def ToMatcherOps[T](x: T) = new MatcherOps[T](x) 

    implicit val StringFormatter = new Formatter[String] { 
    def format(x: String) = "StringFormatter" 
    } 

    implicit val ListOfIntFormatter = new Formatter[List[Int]] { 
    def format(x: List[Int]) = "ListOfIntFormatter" 
    } 

    implicit def AnyFormatter[T] = new Formatter[T] { 
    def format(x: T) = "AnyFormatter" 
    } 

    def main(args: Array[String]): Unit = { 
    List(1,2) must_== List(1,2,3) // ListOfIntFormatter 
    "string" must_== "another string" // StringFormatter 
    1 must_== 2 // AnyFormatter 
    1 must_== false // type mismatch 
    } 
}