Scalaでperlのorみたいなやつ
ScalaでPerlのorみたいに、val a:String = foo or "bar" のように、fooがnullとか""だったら"bar"が設定されるようにしたい。
使いどころはあまりないと思うけど、練習がてら作ってみたらエライ大変だった。
はまったのは、implicit parameterを適用する際の型パラメータの共変、反変のところ。
チェック対象の変数の型によって、どんな状態だと"空"だと判断するのを、PartialFunctionとしてimplicit parameterで定義しようとしてやられました。
あとで詳しい解説書きます。
object OrOp{ class OrOp[T]( v:T) { def or( f:() => T )( implicit orPf:OrPF[T,T] ) = { if( orPf.pf.isDefinedAt( v ) ) f() else v } def or( other:T )( implicit orPf:OrPF[T,T] ) = { if( orPf.pf.isDefinedAt( v ) ) other else v } } implicit def any2OrOp[T]( v:T ) = new OrOp(v) class OrPF[-T,+U]( val pf:PartialFunction[T,U] ) implicit val anyrefPF:OrPF[AnyRef,AnyRef] = new OrPF[AnyRef,AnyRef]({ case null => null }) implicit val stringPF:OrPF[String,String] = new OrPF[String,String]({ case null => null case xs:String if xs.size == 0 => xs }) val opf:PartialFunction[Option[Any],Option[Nothing]] = { case null => null case None => None } implicit val optionPF:OrPF[Option[Any],Option[Nothing]] = new OrPF[Option[Any],Option[Nothing]]( opf ) val lpf:PartialFunction[List[Any],List[Nothing] ]= { case null => null case Nil => Nil } implicit val listPF:OrPF[List[Any],List[Nothing]] = new OrPF[List[Any],List[Nothing]]( lpf ) val cpf:PartialFunction[Collection[Any] ,Collection[Nothing] ] = { case null => null case xs if xs.size == 0 => null } implicit val collectionPF: OrPF[Collection[Any],Collection[Nothing]] = new OrPF[Collection[Any],Collection[Nothing]]( cpf ) }
実行すると
scala> import OrOp._ import OrOp._ scala> val l:List[Int] = Nil l: List[Int] = List() scala> l or List(1,2,3) res24: List[Int] = List(1, 2, 3) scala> val c:Collection[String] = Set() c: Collection[String] = Set() scala> c or Set("foo","bar") res25: Collection[String] = Set(foo, bar) scala> val o:Option[List[Int]] = None o: Option[List[Int]] = None scala> o or Some(List(1,2)) res26: Option[List[Int]] = Some(List(1, 2))