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"

にコンパイル ( scalac -Xprint:typer) されます

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

しかし、私はこれがコンパイルされないことを期待します:

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

代わりに、コンパイル ( scalac -Xprint:typer) します。

$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 が 2 回呼び出されています。

暗黙のフォーマッターを邪魔にならないようにすると:

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( scalac -Xprint:typer) を提供することはできません:

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

これを回避する方法はありますか?ありがとう

4

1 に答える 1

0

That's what I came up with. Moving the implicit formatter parameter from the MatherOps class to it's methods.

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
  }
}
于 2013-10-09T14:33:20.157 に答える