2017-01-24 7 views
0

それはOption[String]ScalaのジェネリックtoOptionは期待通りに動作しない

を返す私は Option[T] に任意の型を変換する汎用的な関数を記述するために抱き合わせていますが、何とか期待どおりに動作していないここに

scala> def toOption[T](obj:Any):Option[T] = obj match { 
| case obj:T => Some(obj) 
| case _ => None 
| } 
<console>:11: warning: abstract type pattern T is unchecked since it is eliminated by erasure 
    case obj:T => Some(obj) 
      ^
toOption: [T](obj: Any)Option[T] 

それはOKらしいです

scala> toOption[String]("abc") 
res0: Option[String] = Some(abc) 

が、ここではSome(def)を返す代わりにNone

scala> toOption[Int]("def") 
res1: Option[Int] = Some(def) 

私はこの一般的な関数を作成する適切な方法を理解することができないし、なぜそれが起こっているのか理解していない、私はすでに多くの投稿を読んでいるとスカラーの型消去についての質問を、具体的な説明は大きな助けになるでしょう!

答えて

2

ScalaはJavaのようにジェネリックに型消去を使用するため、タイプTは実行時には使用できません。だから、あなたのテストcase obj:Tは望みの効果がなく、コンパイラはあなたにその事実を警告しました。

ClassTagを使用すると、実行時にタイプ情報を利用できるようになります。 ClassTagはすでにそのunapply方法でオプションへの変換を実装します。

scala> import scala.reflect.{classTag,ClassTag}; 
import scala.reflect.{classTag, ClassTag} 

scala> def toOption[T: ClassTag](obj: Any): Option[T] = classTag[T].unapply(obj); 
toOption: [T](obj: Any)(implicit evidence$1: scala.reflect.ClassTag[T])Option[T] 

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

scala> toOption[String](1) 
res2: Option[String] = None 

scala> toOption[String]("one") 
res3: Option[String] = Some(one) 

scala> toOption[Int]("one") 
res4: Option[Int] = None 

しかし、あなたがここに見るように、これは一般的なタイプのために動作しません:

scala> toOption[List[Int]](List("one", "two")) 
res5: Option[List[Int]] = Some(List(one, two)) 

scala> res5.get 
res6: List[Int] = List(one, two) 

scala> res6(0) + res6(1) 
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer 
    at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:101) 
    ... 29 elided 
+0

私はもう少し理解していますが、この 'scala> def toOption [T <:Any](obj:Any)を試してみましょう:Option [T] = obj match { | case obj:String => Some(obj) | case _ => None 'それは働くでしょうか? – superDoss

0

あなたがの2種類の引数を持っている場合があります機能 - 希望のタイプと実際の型:

def toOption[Desired, Actual](obj:Actual):Option[Desired] = ??? 

そして、私は推測、あなたは型が一致した場合にのみSomeを返すようにしたいです:

def toOption[Desired, Actual](obj:Actual) 
    (implicit ev: Actual =:= Desired = null):Option[Desired] = 
    if(ev == null) 
    None 
    else 
    Some(ev(obj)) 

ここでは、Scalaが両方の引数を推論できないときに不都合な場合がある2つの型引数があります。

toOption[String]("def") == Some("def") 
toOption[Int]("def") == None 

(あなたはまた、マイルに見えるかもしれません:それは同じように使用される可能性があります

class toOptionImpl[Desired] { 
    def apply[Desired, Actual](obj:Actual) 
    (implicit ev: Actual =:= Desired = null):Option[Desired] = 
    if(ev == null) 
     None 
    else 
     Some(ev(obj)) 
} 
def toOption[Desired] = new toOptionImpl[Desired] 

:あなたは(単一型の引数を与えて)使用したのと同じ構文については、次のようなトリックを使用することができますSabinの多相関数https://milessabin.com/blog/2012/04/27/shapeless-polymorphic-function-values-1/https://milessabin.com/blog/2012/05/10/shapeless-polymorphic-function-values-2/

関連する問題