简体   繁体   English

递归地使用TypeTag调用函数

[英]Calling a function with TypeTag recursively

I'm playing with Scala TypeTag. 我在玩Scala TypeTag。 I want to recursively call a function with a TypeTag parameter. 我想用TypeTag参数递归调用一个函数。 Here is a simplified example of what I'm trying to do: 这是我要执行的操作的简化示例:

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")))

}

This code compiles and runs: 该代码编译并运行:

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)

Couple of questions: 几个问题:

  1. How to pass the type information when the recursive call is made? 进行递归调用时如何传递类型信息?
  2. Is there a way to make this pattern matching a little less ugly? 有没有办法使这种模式匹配不那么难看?

It's not a recursion problem - your "Unwrapped type..." line never prints. 这不是递归问题-您的“ Unwrapped type ...”行永远不会打印。 I suspect the problem is that optionType , in this case Some[String] , is not a strict subtype of Option[_] which expands to Option[A] forSome {type A} . 我怀疑问题在于,在这种情况下, Some[String] optionType不是Option[_] Option[A] forSome {type A} ,后者会扩展为Option[A] forSome {type A}

In this specific instance perhaps you want to test whether optionType <:< Option[Any] , since Option is covariant? 在这种特定情况下,您可能想测试optionType <:< Option[Any] ,因为Option是协变的? Or perhaps you could check that the first argument of the TypeRef is Option . 或者,您可以检查TypeRef的第一个参数是否为Option

Once you've fixed that, I don't think it's possible to obtain the TypeTag for a parameter since they're always generated by the compiler, but since you're only using the Type you can make the method work with those instead: 修复此问题后,我认为无法获取参数的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])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM