2011-10-24 8 views
9

How to write "asInstanceOfOption" in Scalaの答えにあるasInstanceOfの安全なバージョンasInstanceOfOptの便利な実装があります。asInstanceOfOpt [T]ここでT <:Any Anyを書く方法

class WithAsInstanceOfOpt(obj: AnyRef) { 
    def asInstanceOfOpt[B](implicit m: Manifest[B]): Option[B] = 
    if (Manifest.singleType(obj) <:< m) 
     Some(obj.asInstanceOf[B]) 
    else 
     None 
} 

これはどれをサポートするために書き換えることができます:Scalaの2.9.1は、このソリューションは、今だけAnyRefで動作する、ように見えますか?

答えて

1

Scala APIを見ると、関数singleTypeはAnyRef型のパラメータをとります。私はこの決定の背景を本当に知っていませんが、それを回避する必要があるようです。メソッドsingleTypeを使用する代わりに、基本的にどのクラスでもマニフェストを作成できるclassTypeメソッドを使用することをお勧めします。もう少しコードを追加しますが、次のようになります。

class WithAsInstanceOfOpt(obj : Any) { 
    def asInstanceOfOpt[B : Manifest] : Option[B] = // [B : Manifest] is shorthand for [B](implicit m : Manifest[B]) 
    if (Manifest.classType(manifest, obj.getClass) <:< manifest) 
     Some(obj.asInstanceOf[B]) 
    else None 
} 
+0

上のコードはボクシングのために動作しません。 '' 1.asInstanceOfOpt [Int] 'は' None'を返し、 '1.asInstanceOfOpt [java.lang.Integer] 'は' Option [Integer] '型の' Some(1) 'を返します。手動でタイプをマッピングする必要があります(私は解決策を投稿します)。 – Blaisorblade

0

ここでは2.9.x用の作業コードです。 2.10.xの非推奨警告が表示されますが、Manifestの代わりにClassTagを使用し、erasureの代わりにruntimeClassを使用すると、それらが修正されます。

//Precondition: classS must have been produced through primitiveToBoxed, because v will be boxed. 
def ifInstanceOfBody[T, S](v: T, classS: Class[_]): Option[S] = { 
    if (v == null || !classS.isInstance(v)) 
    None 
    else 
    Some(v.asInstanceOf[S]) 
} 
object ClassUtil { 
    import java.{lang => jl} 

    private val primitiveToBoxedMap = Map[Class[_], Class[_]](
    classOf[Byte] -> classOf[jl.Byte], 
    classOf[Short] -> classOf[jl.Short], 
    classOf[Char] -> classOf[jl.Character], 
    classOf[Int] -> classOf[jl.Integer], 
    classOf[Long] -> classOf[jl.Long], 
    classOf[Float] -> classOf[jl.Float], 
    classOf[Double] -> classOf[jl.Double], 
    classOf[Boolean] -> classOf[jl.Boolean], 
    classOf[Unit] -> classOf[jl.Void] 
) 
    def primitiveToBoxed(classS: Class[_]) = 
    primitiveToBoxedMap.getOrElse(classS, classS) 
} 
class IfInstanceOfAble[T](v: T) { 
    def asInstanceOfOpt[S](implicit cS: Manifest[S]): Option[S] = 
    ifInstanceOfBody[T, S](v, ClassUtil.primitiveToBoxed(cS.erasure)) 
} 
implicit def pimpInstanceOf[T](t: T) = new IfInstanceOfAble(t) 

試験結果:

scala> 1.asInstanceOfOpt[Int] 
res9: Option[Int] = Some(1) 

scala> "".asInstanceOfOpt[String] 
res10: Option[String] = Some() 

scala> "foo".asInstanceOfOpt[String] 
res11: Option[String] = Some(foo) 

scala> 1.asInstanceOfOpt[String] 
res12: Option[String] = None 

scala> "".asInstanceOfOpt[Int] 
res13: Option[Int] = None 

コード私は、私は他の場所でifInstanceOfBodyを再利用する私の既存のコードベースから、それを取った主な理由は、ここで必要とされるよりやや冗長です。 asInstanceOfOptにインライン展開するとコードが少し修正されますが、そのほとんどはprimitiveToBoxedMapであり、Scala標準ライブラリで利用可能なものを見つけることができないと私を信じています。

0

あなたはマイルセービンからshapelessのTypeableを使用することができます。

Type casting using type parameter

それはプリミティブとボクシングを処理します。

scala> import shapeless._; import syntax.typeable._ 
import shapeless._ 
import syntax.typeable._ 

scala> 1.cast[Int] 
res1: Option[Int] = Some(1) 

scala> 1.cast[String] 
res2: Option[String] = None 

scala> "hello".cast[String] 
res4: Option[String] = Some(hello) 

scala> "foo".cast[Int] 
res5: Option[Int] = None 

あなたはそれが書かれているかを確認するには、ここのソースを見ることができます:

https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/typeable.scala

関連する問題