繁体   English   中英

是否有可能在Scala中找到类型系统级别的常见超类型?

[英]Is it possible to find a common supertype on type-system level in Scala?

是否有可能在Scala中创建一个类型别名(或类似的东西),它接受两个参数并返回它们的常见超类型? 换句话说,我正在尝试使用此签名找到一些东西:

type CommonSupertype[A, B] // can't be more specific

这些都适用:(伪代码)

CommonSupertype[String, Int] = Any
CommonSupertype[JButton, JPanel] = JComponent

等等

我自己无法找到它,但我不能使用其他替代参数,因为我必须遵循预先指定的接口。

(不是一个完整的解决方案,但可能会给出一些想法)

Scala的一个令人印象深刻的功能是它能够在将橙色附加到苹果列表时返回水果列表。 它的值很好,正是因为你推断了泛型类型。

import scala.reflect.Manifest

def CommonSuperType[A, B >: A : Manifest](a:A, b:B) = manifest[B]  

它有效(有点):

scala> CommonSuperType(new JButton, new JPanel)
res42: Manifest[javax.swing.JComponent with javax.accessibility.Accessible] = javax.swing.JComponent with javax.accessibility.Accessible

下一步是将此技巧提升到更高级别的类型(未经测试)。
半成品解决方案包括从类型创建值(参见此答案 ):

class CommonSuper[A:Manifest, B:Manifest] {
   def make[T:Manifest] = manifest[T].erasure.newInstance.asInstanceOf[T]
   val instanceA = make[A]
   val instanceB = make[B]
   def getType = CommonSuperType(instanceA, instanceB)
}   

但我陷入了这种不直观的不一致:

scala> val test = new CommonSuper[JButton, JPanel]

scala> test.getType
res66: Manifest[Any] = Any

scala> CommonSuperType(test.instanceA, test.instanceB)
res67: Manifest[javax.swing.JComponent with javax.accessibility.Accessible] = javax.swing.JComponent with javax.accessibility.Accessible

无论如何,虽然我喜欢这种类型的问题(关于类型的问题),但在这里它闻起来像一个XY问题

我可以给你一个特性CommonSupertype[A, B]和一个隐式生成器函数,所以你可以在需要的地方只需要这个trait的隐式实例,它将包含公共超类型(作为依赖类型)。

这不是我的想法,它实际上从Miles Sabin的这篇文章中略微调整过。

我所做的唯一改变是,虽然他使用¬¬[C] <:< (A ∨ B)作为C型是A或B的子类型的证据,但我已经颠倒了子类型方向(所以: (A ∨ B) <:< ¬¬[C] )检查A和B都是C的子类型。

import scala.reflect.ClassTag

object Main extends App {
  type ¬[A] = A => Nothing
  type ∨[T, U] = ¬[¬[T] with ¬[U]]
  type ¬¬[A] = ¬[¬[A]]

  trait CommonSupertype[A, B] {
    type λ
    def tag: ClassTag[λ]
  }
  // The ClassTag is only so I can get ahold of the type's name at runtime
  implicit def commonSupertype[A, B, C : ClassTag](implicit C: (A ∨ B) <:< ¬¬[C]): CommonSupertype[A, B] { type λ = C } =
    new CommonSupertype[A, B] { type λ = C; def tag = implicitly[ClassTag[C]] }

  trait Pet
  class Dog extends Pet
  class Cat extends Pet
  def check[A, B](implicit x: CommonSupertype[A, B]) = {
    // This just prints the common type, but you could use the type (x.λ) directly
    println(x.tag.toString())
  }
  check[Dog, Cat]
  check[Dog, Double]
}

给我们:

Main.Pet
Any

您可以获取最不常见的超类型的typeTag,然后提取其类型(请参阅如何从TypeTag [T]或scala中的任何其他泛型中捕获T?

import scala.reflect.runtime.universe._
import scala.util._

def t[A, B] = (null.asInstanceOf[A], null.asInstanceOf[B])
implicit class RichTuple[A: TypeTag](a: (A, A)) {def common = typeTag[A]}

implicit class RichT[T: TypeTag](a: T) {//just helper for working with typetags 
   def asInstanceOfT[U](t: TypeTag[U]) = a.asInstanceOf[U]
   def hasSameTypeWith[U](t: TypeTag[U]) = typeTag[T] == t
}

用法

scala> t[String, String].common
res87: reflect.runtime.universe.TypeTag[String] = TypeTag[String]

scala> t[String, Int].common
res88: reflect.runtime.universe.TypeTag[Any] = TypeTag[Any]

scala> ("aa" : String).hasSameTypeWith(t[String, String].common)
res105: Boolean = true

scala> ("aa" : String).hasSameTypeWith(t[String, Int].common)
res106: Boolean = false

scala> ("aa" : String).asInstanceOfT(t[String, Int].common)
res109: Any = aa 

scala> ("aa" : String).asInstanceOfT(t[Int, Int].common)
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer

对于isInstanceOf,请参阅如何知道对象是否是TypeTag类型的实例?

唯一的限制是你不能获得常见的类型参数超类型 - 它将永远被删除为任何。

暂无
暂无

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

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