Lambdaカクテル

Common LISPが好きなWeb屋さんです 自宅サーバやフロントエンドもできます

implicit defでインスタンスを変換する

ある型Baseを引数に取るようなコンテクストで他の型のインスタンスを使おうとすると、当然、通常ならばコンパイラがエラーを吐く。

//example
class DrinkContent(receipt: String) {
 val receiptVal = receipt
 def drink = {System.out.println(receiptVal)}
}
class PetBottle(content: DrinkContent) {
 var contentVal = content
}


REPL> new DrinkContent("Orange") .drink // "Orange"
REPL> new PetBottle(new DrinkContent("Apple")) .drink // Error: drinkメソッドはPetBottleには存在しない

このように、ある型を暗黙に別の型に変換したいときがある。
implicit defはこの問題を解決する。
implicitを付けてdefされた関数は、変換前の型のインスタンスから変換後の型のインスタンスへの変換を自動的に行なうためのハンドラのようにふるまう。
このテクニックにより、instance.getXX()のような処理を隠匿することができる。
ただし使いすぎると変換を追えなくなりバグのもとなので使用はほどほどに。

//example
class DrinkContent(receipt: String) {
 val receiptVal: String = receipt
 def drink = {System.out.println(receiptVal)}
}
class PetBottle(content: DrinkContent) {
 var contentVal: DrinkContent = content
}
implicit def PetBottle2DrinkContent(pet: PetBottle): DrinkContent = pet.contentVal

REPL> val OrangeJuiceBottle = new PetBottle(new DrinkContent("Orange"))
REPL> OrangeJuiceBottle.drink // "Orange": 自動的にPetBottle2DrinkContentが呼び出され、DrinkContentのdrinkが呼ばれる

このテクニックは、既存のSealed属性のクラスに新たな機能を追加するときにも使用できる。