【问题标题】:Multiple lower type bounds in ScalaScala中的多个下限类型
【发布时间】:2011-05-24 23:23:26
【问题描述】:

我注意到tuple.productIterator 总是返回一个Iterator[Any] 并想知道是否不能设置多个下限(因此它可能是最低通用超类型的迭代器)。

我尝试并搜索了一下,但只找到了this 多个上限的问题。

这是我对如何定义迭代器类型的测试:

def f[A,B](a:A, b:B) = List(a,b)
// return type is List[Any]

def f[A,B, T >: A "and" T >: B](a:A, b:B) = List[T](a,b)
// doesn't compile, but
//  f(1, true) should give a List[AnyVal] and
//  f("x", "y") a List[String]

这是 JVM 的限制吗?


编辑: 这是一个稍微大一点的例子,当 T 应该在方法中定义时,使用 IttayD 方法似乎无法解决:
class Foo[A, B](a: A, b: B) {
  def f[T >: A] = List[T](a) // works
  def g[T >: A "and" T >: B] = List[T](a) // doesn't work
}

【问题讨论】:

    标签: scala jvm type-systems


    【解决方案1】:

    对于ABT 同时被编译器绑定的简单情况,IttayD's answer 工作正常:

    def f[T, A <: T,B <: T](a:A, b:B) = List[T](a,b)
    

    AB 已经绑定到您的 class Foo[A, B] 示例中时,您需要引入临时虚拟变量以让编译器完成这项工作:

    class Foo[A, B](a: A, b: B) {
      def g[T, A1 >: A <: T, B1 >: B <: T] = List[T](a: A1, b: B1)
    }
    

    (为了清楚起见:A1 &gt;: A &lt;: T 表示A1 类型必须是A 的超类型和T 的子类型,而不是A 是两者的子类型@ 987654335@ 和T。)

    A1B1 仅用于推断T 的正确类型。如果编译器必须推断它们,它们将解析为A1 = AB1 = B,然后T 作为最具体的类型,它是AB 的超类。

    不过,编译器没有意识到的一件事是,通过传递性,我们同时拥有T &gt;: AT &gt;: B,这直接来自关于A1B1 的约束。我们需要帮助解决类型归属问题。

    现在,Product#productIterator 无法使用这种技术,因为它是在我们甚至不知道 AB 的地方定义的,或者实际上在具体子类中有多少类型参数。

    【讨论】:

      【解决方案2】:

      听起来你需要的是一个 HList:http://apocalisp.wordpress.com/2010/07/06/type-level-programming-in-scala-part-6a-heterogeneous-list%C2%A0basics/

      回答具体问题:

      scala> def f[T, A <: T,B <: T](a:A, b:B) = List[T](a,b)
      f: [T, A <: T, B <: T](a: A, b: B)List[T]
      
      scala> f(1, true)
      res0: List[AnyVal] = List(1, true)
      
      scala> f("x", "y")
      res1: List[java.lang.String] = List(x, y)
      

      【讨论】:

      • 这几乎相当于一个简单的def f[T](a:T, b:T) = List[T](a,b)...
      • f(1,2.0) 将导致 List[Double] = List(1.0, 2.0)
      • 如果AB 被定义在外部范围内会怎样?我是否需要将 T 的定义也移到那个外部范围? (@IttayD 修复了示例)
      • @IttayD 你的更新很危险:看看返回类型,List[Int with Double]... 有趣的类型。你让编译器相信它是一个都是 Ints 和 Doubles 的元素列表。试试这个并得到一个不需要的ClassCastExceptionval res = (new Foo(1, "hi")).g; res.head.size
      • 类型归属不起作用这一事实暗示编译器对此不满意。
      猜你喜欢
      • 2015-10-15
      • 1970-01-01
      • 2018-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-07
      相关资源
      最近更新 更多