読者です 読者をやめる 読者になる 読者になる

( ꒪⌓꒪) ゆるよろ日記

( ゚∀゚)o彡°オパーイ!オパーイ! ( ;゚皿゚)ノシΣ フィンギィィーーッ!!!

Scalaでperlのorみたいなやつ

ScalaPerlの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))