2017-11-26 11 views
3

thisの記事で、implicitsを使用してScalaで型式をシミュレートする方法について説明しています。Scalaのtypeclassパターンの暗黙の定義の実行時コスト

私が間違っていない場合、再帰的インスタンス宣言の型クラスメソッド(Printer a => Printer (Option a))が使用されるたびに、新しいインスタンスが実行時に構築されます。ここにコードがあり、printが使用されるたびに、新しいPrinterインスタンスが実行時に作成されます。特定のタイプ(この場合はOption[Int])用に作成されたインスタンスを再利用する方法はありますか?

trait Printer[T] { 
    def print(t: T): String 
} 

object Printer { 
    implicit val intPrinter: Printer[Int] = new Printer[Int] { 
    def print(i: Int) = s"$i: Int" 
    } 

    implicit def optionPrinter[V](implicit pv: Printer[V]): Printer[Option[V]] = 
    new Printer[Option[V]] { 
     println("New Option Printer") 
     def print(ov: Option[V]) = ov match { 
     case None => "None" 
     case Some(v) => s"Option[${pv.print(v)}]" 
     } 
    } 

} 

object Main { 
    def print[T](t: T)(implicit p: Printer[T]) = p.print(t) 

    def main(args: Array[String]): Unit = { 
    val res3 = print(Option(1)) 
    val res4 = print(Option(2)) 
    println(s"res3: ${res3}") 
    println(s"res4: ${res4}") 
    } 
} 

// New Option Printer 
// New Option Printer 
// res3: Option[1: Int] 
// res4: Option[2: Int] 

答えて

3

あなたは正しいです。あなたの例では、すべての呼び出しで新しいインスタンスが作成されます。しかし、それに対処するにはいくつかの方法があります。私の経験では、次の経験則に従います。

まず、追加インスタンスが実際に問題であることを確認してください。 パフォーマンスに関連すると確信できる場合は、多くのvalをコーディングするだけで対応できます。

object Printer { 
    implicit val intPrinter: Printer[Int] = new Printer[Int] { 
    def print(i: Int) = s"$i: Int" 
    } 

    // make sure this is not visible, as you do not want to have productive code create new instances on demand 
    private[this] def optionPrinter[V](implicit pv: Printer[V]): Printer[Option[V]] = 
    new Printer[Option[V]] { 
     println("New Option Printer") 
     def print(ov: Option[V]) = ov match { 
     case None => "None" 
     case Some(v) => s"Option[${pv.print(v)}]" 
     } 
    } 

    implicit val intOptPrinter: Printer[Option[Int]] = optionPrinter[Int] 
} 

私は、shapelessを使用するとさらに高度な解決策が可能だと思います。しかし、imhoは、型クラスと型レベルプログラミングの深い理解が必要であることを忘れないでください。

関連する問題