如何使用变量作为Scala类型参数?

时间:2016-10-06 00:06:41

标签: scala

我想做以下事情:

val aoeu = List((0, 1), (0, 1, 2))
List(Tuple2, Tuple3).foreach { snth =>
  println(aoeu.filter(_.isInstanceOf[snth]).map(_.asInstanceOf[snth]))
}

这可能吗?

1 个答案:

答案 0 :(得分:0)

正如我所提到的,Scala中的类型安全和(相对)容易传入一个类型参数并获取一个值。另一种方式是什么是困难的,而不是编译时类型安全的。对于你现在的问题,答案是......有点。我们可以做的是定义一个类型类来捕获安全转换的想法,为我们感兴趣的类型设置一些实例,然后进行操作。所以这就是我所拥有的:

import scala.util.Try

/**
A typeclass to represent safe casting behaviour.
*/
trait HasInstance[A] { def apply(any: Any): Option[A] }

object HasInstance {
  /**
  A helper to quickly create a typeclass instance.
  */
  private class Impl[A](_apply: Any => Option[A])
    extends HasInstance[A] {
    override def apply(any: Any): Option[A] = _apply(any)
  }

  /* Instances for standard types. */

  implicit val int: HasInstance[Int] =
    new Impl(any => Try(any.asInstanceOf[Int]).toOption)

  implicit def tuple2[A, B]: HasInstance[Tuple2[A, B]] =
    new Impl(any => Try(any.asInstanceOf[Tuple2[A, B]]).toOption)

  implicit def tuple3[A, B, C]: HasInstance[Tuple3[A, B, C]] =
    new Impl(any => Try(any.asInstanceOf[Tuple3[A, B, C]]).toOption)
}

object Test {
  def test(): Unit = {
    val xs = List((0, 1), (0, 1, 2))

    // Flatmap will automatically filter out `None` values.

    println(xs flatMap implicitly[HasInstance[Tuple2[Int, Int]]].apply)
    // ==> List((0, 1))

    println(
      xs flatMap implicitly[HasInstance[Tuple3[Int, Int, Int]]].apply)
    // ==> List((0, 1, 2))
  }
}

请注意,我们仍然无法捕获列表中的实例,因为它们的类型会强制Scala向上转换为AnyRef以将它们存储在一起。如果你想拥有并映射异构列表,那么你就处于无形区域。实际上,您可能仍然是因为您可能希望进行泛型推导以便轻松派生HasInstance的实例。