繁体   English   中英

如何在编译时检查类型是否为元组

[英]How to check if types are Tuple in compile time

我有以下案例类:

case class MyClass[A,B](a:A, b:B)

我想向MyClass添加一个像 unzip 这样的函数,所以如果AB是元组类型,那么我想像下面这样提取它们:

val item = MyClass[(Int,String), (Int,String)]((2,"two"), (3,"three"))
val item_left = MyClass(item.a._1, item.b._1)
val item_right = MyClass(item.a._2, item.b._2)

我应该如何做到这一点并在编译时检查元组的类型? 我不想在伴随对象中定义它,我希望它是MyClass一个函数。 我知道我可以定义一个implicit函数,但这是唯一的方法吗?

您可以使用<:<类型类来证明ABTuple2子类型,以便您可以分解它们。 也就是说,我们可以编写一个unzip方法来拥有一些自由类型参数,这些参数将是分解后的纵坐标类型(称为A1A2B1B2 )。 然后,我们需要证明A <:< (A1, A2)B <:< (B1, B2)证据。 如果子类型关系为真,编译器将找到这些类型类的实例,我们可以使用它们来完成转换。 也就是说, A <:< (A1, A2)扩展了函数A => (A1, A2)

case class MyClass[A, B](a: A, b: B) {
  def unzip[A1, A2, B1, B2](implicit
      ev1: A <:< (A1, A2),
      ev2: B <:< (B1, B2)
    ): (MyClass[A1, A2], MyClass[B1, B2]) = {
    val (a1, a2) = ev1(a)
    val (b1, b2) = ev2(b)
    (MyClass(a1, a2), MyClass(b1, b2))
  }
}

在行动:

scala> MyClass((2, "two"), (3, "three")).unzip
res6: (MyClass[Int,String], MyClass[Int,String]) = (MyClass(2,two),MyClass(3,three))

对于非元组:

scala> MyClass(1, 2).unzip
<console>:14: error: Cannot prove that Int <:< (A1, A2).
       MyClass(1, 2).unzip
                     ^

迈克尔的回答非常好。 如果您愿意在案例类的声明中要求 A 和 B 是 Product 的子类型,您也可以走一条更简单的路线:

case class MyClass[A <: Product, B <: Product](a:A, b:B) {
  def item_left = (a.productIterator.toList(0), b.productIterator.toList(0))
  // etc.
}

现在,你可以写:

val x = MyClass((2,"two"), (3,"three"))
x.item_left

这导致:

(2,3)

类型(任何,任何)。

我建议这个替代方案只是因为我不清楚你愿意有多复杂。 我希望不会引起任何反对票;)

暂无
暂无

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

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