Pimp My Library
標準機能やサードパーティライブラリのクラスを拡張したいときに使う。
object ImplicitInt { implicit class RichInt(val x: Int) { def negate: Int = -x def square: Int = x * x } }
上記のような implicit class を作っておいてimport すると、Int型の変数で squareメソッド、negate メソッドが使えるようになる。
import ImplicitInt._ object Main { def main(args: Array[String]): Unit = { // pimp my library val x = 100 println(x.square) // 10000 println(x.negate) // -100 } }
Implicit Conversion
暗黙の型変換。
case class Rational(real: Double, imag: Double) { def +(that: Rational) = Rational(real + that.real, imag + that.imag) } object Rational { implicit def double2Rational(x: Double): Rational = new Rational(x, 0) }
上記のように複素数を扱うクラスを定義したとする。複素数と実数の足し算をしたい場合、implicit conversion を使うと以下のように書ける。わざわざ Double から Rational クラスを明示的につくらなくていいので便利。
object Main { def main(args: Array[String]): Unit = { val x = Rational(1.0, 1.0) val y = x + 2.0 println(y) // Rational(3.0,1.0) } }
Implicit Parameter
暗黙的なパラメータ。実行コンテキストなどのパラメータを暗黙的にメソッドに渡してくれる。
import scala.concurrent.{ExecutionContext, Future} class RemoteCall { def get(x: Int)(implicit ex: ExecutionContext): Future[Int] = Future { println("heavy remote call...") Thread.sleep(5000) x } }
上記のような重い処理があって、メインスレッドとは別のスレッドで実行したいとする。 ExecutionContext を implicit で受け取れるように定義されているため、以下のように実行コンテキストを渡すことができる。
import java.util.concurrent.Executors import scala.concurrent.{ExecutionContext, ExecutionContextExecutorService} import scala.util.{Failure, Success} object Main { def main(args: Array[String]): Unit = { implicit val ex: ExecutionContextExecutorService = ExecutionContext.fromExecutorService(Executors.newSingleThreadExecutor()) val remoteCall = new RemoteCall remoteCall.get(123) onComplete { case Success(r) => println(r) ex.shutdown() case Failure(t) => println(t.getMessage) } println("do something else") } }
他にもデータベース接続をするときに、接続まわりを担当するクラスを implicit parameter で渡すなどの使い方がある。
0 件のコメント:
コメントを投稿