2014-10-24 2 views
0

저는 Scala TypeTag를 가지고 놀고 있습니다. TypeTag 매개 변수를 사용하여 재귀 적으로 함수를 호출하려고합니다.재귀 적으로 TypeTag를 사용하여 함수 호출

import scala.reflect.runtime.universe._ 

object TypeTagTest extends App { 

    def intValue[T](value: T)(implicit tag: TypeTag[T]): Int = { 
    tag.tpe match { 
     // integer 
     case intType if intType <:< typeOf[Int] => 
     value.asInstanceOf[Int] 
     // string 
     case stringType if stringType <:< typeOf[String] => 
     value.asInstanceOf[String].toInt 
     // option of either string or integer 
     case optionType @ TypeRef(_, _, typeArg::Nil) if optionType <:< typeOf[Option[_]] => 
     println(s"Unwrapped type is $typeArg") 
     val option = value.asInstanceOf[Option[_]] 
     option.map { optionValue => 
      // how to pass the typeArg here? 
      intValue(optionValue) 
     }.getOrElse(0) 
    } 
    } 

    println(intValue(1)) 
    println(intValue("1")) 
    println(intValue(Some("1"))) 

} 

이 코드를 컴파일 및 실행 : 질문의

1 
1 
Exception in thread "main" scala.MatchError: Any (of class scala.reflect.internal.Types$TypeRef$$anon$6) 
    at TypeTagTest$.intValue(TypeTagTest.scala:7) 
    at TypeTagTest$$anonfun$intValue$2.apply(TypeTagTest.scala:19) 
    at TypeTagTest$$anonfun$intValue$2.apply(TypeTagTest.scala:18) 
    at scala.Option.map(Option.scala:145) 

커플 :

  1. 어떻게 유형의 정보를 전달하기 위해 여기에 내가 할 노력하고있어의 간단한 예입니다 재귀 호출이 이루어질 때?
  2. 조금 더 못생긴이 패턴을 만드는 방법이 있습니까?
+0

1. 재귀 함수는 제네릭 형식의 관점에서 일반 함수와 다르지 않습니다. 문제는 여기에 타입 소거로 인해'optionValue' 타입을 사용할 수 없으므로 암시적인'TagType'은'TypeTag [Any]'가 될 것이고 당신은 그 케이스에 대한 경비가없고 당신의 디폴트가 없습니다 패턴 매치가 발생하면'MatchError'가 던져 질 것입니다. –

+0

2. 나는 언제나 방법이 있다고 말한다. 이러한 모든 작업을 실제로 수행해야합니까, 아니면 실제 요구 사항을 보여주기위한 것일까요? 왜냐하면 이것이 정확히 당신이하고 싶은 일이라면, 이렇게하는 것은 불필요하고 이상합니다. –

+0

실제 문제를 보여주는 단지의 예입니다. –

답변

0

"재 포장되지 않은 유형 ..."줄이 결코 인쇄되지 않습니다. 재귀 문제는 아닙니다. 나는이 문제가 optionType이고,이 경우 Some[String]이 의 확장 하위 유형이 아니며 Option[A] forSome {type A}으로 확장되었다고 생각합니다.

Option은 공변 (covariant)이기 때문에 optionType <:< Option[Any]이 있는지 여부를 테스트하려는 경우가 있습니까? 또는 TypeRef의 첫 번째 인수가 Option인지 확인할 수 있습니다.

일단 수정하면 TypeTag을 매개 변수로 가져올 수 없다고 생각합니다. 항상 컴파일러에서 생성되기 때문에 Type 만 사용하기 때문에이 방법을 사용할 수 있습니다 그 대신에 :

def intValueInner(value: Any, tpe: Type) = tpe match { 
    ... 
    case optionType @ TypeRef(_, _, typeArg::Nil) if optionType <:< typeOf[Option[Any]] => 
    value.asInstanceOf[Option[_]].map(v => intValueInner(v, typeArg)).getOrElse(0) 
} 
def intValue[T: TypeTag](t: T) = intValueInner(t, typeOf[T]) 
+0

감사! 유형을 전달하면 나를 위해 작동합니다. –

관련 문제