Scala 中的 F 有界多态性 [英] F-Bounded Polymorphism in Scala

查看:33
本文介绍了Scala 中的 F 有界多态性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是 Scala 2.10-RC5

I am using Scala 2.10-RC5

这是我的代码:

object Fbound {
    abstract class E[A <: E[A]] {
        self: A =>
        def move(a: A): Int
    }
    class A extends E[A] {
        override def toString = "A"
        def move(a: A) = 1
    }
    class B extends E[B] {
        override def toString = "B"
        def move(b: B) = 2
    }
    def main(args: Array[String]): Unit = {
        val a = new A
        val b = new B
        val l = List(a, b)
        val t = l.map(item => item.move(null.asInstanceOf[Nothing]))
        println(t)
    }
}

运行程序时出现异常:

Exception in thread "main" java.lang.NullPointerException
    at fb.Fbound$$anonfun$1.apply(Fbound.scala:20)
    at fb.Fbound$$anonfun$1.apply(Fbound.scala:20)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
    at scala.collection.immutable.List.foreach(List.scala:309)
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
    at scala.collection.AbstractTraversable.map(Traversable.scala:105)
    at fb.Fbound$.main(Fbound.scala:20)
    at fb.Fbound.main(Fbound.scala)

我的问题是:

  1. 为什么它通过编译器但在运行时失败?
  2. 在底部添加一行 - val t1 = l.map(item => item.move(item)) 会使编译器失败,为什么?
  1. Why it pass the compiler but fail at runtime?
  2. Adding a line at the bottom - val t1 = l.map(item => item.move(item)) will fail the compiler, why?

推荐答案

您的带有 null.asInstanceOf[Nothing] 的代码可以编译,因为 Nothing 是所有内容的子类,并且,因此,符合 move 所需的类型.不用说,它会在运行时抛出异常.

Your code with null.asInstanceOf[Nothing] compiles because Nothing is a subclass of everything and, as such, complies with the required type for move. Needless to say, it will throw an exception at runtime.

当你尝试编译你给出的第二行时,你会在这个错误的行中得到一些东西:

When you try to compile the second line you gave, you are given something in the lines of this error:

<console>:19: error: type mismatch;
 found   : E[_6(in value $anonfun)] where type _6(in value $anonfun) >: B with A
 <: E[_ >: B with A <: Object]
 required: <root>._6

当您将两个实例放在同一个 List 中时,您丢失了有关它们元素类型的重要信息.编译器无法确保 T >: B with A <: E[_ >: B with A] 类型的元素可以传递给 move> 同类型对象的方法,同样的方法你做不到:

When you put the two instances in the same List, you have lost important information about the type of their elements. The compiler can't ensure that an element of type T >: B with A <: E[_ >: B with A] can be passed to the move method of an object of the same type, the same way that you can't do:

val c: E[_ >: B with A] = new A
val d: E[_ >: B with A] = new B
c.move(d) // note: the _ in c and d declarations are different types!

我对 self-types 的了解不够,无法完全确定这种解释,但在我看来,这是一个类级别的限制,而不是一个实例级别的限制.换句话说,如果你在 E 中丢失了关于类型参数的信息,你不能指望编译器知道 move 参数的特定类型.

I don't know enough about self-types to be completely sure of this explanation, but it seems to me that it is a class-level restriction, and not an instance-level one. In other words, if you lose the information about the type parameter in E, you can't expect the compiler to know about the move argument particular type.

对于实例级别的限制,您有 this.type.如果您将 move 定义为:

For instance-level restrictions, you have this.type. If you define move as:

def move(a: this.type): Int

您的代码可以编译,但我认为这不是您想要的,因为 move 将只接受您正在调用它的 相同实例,这是无用的.

Your code compiles, but I don't think it is what you want, as move will accept only the same instance you are calling it on, which is useless.

我想不出您可以按照自己的意愿强制执行该限制的任何方式.我建议您尝试使用类型变量(即在 E 类中定义类型变量 type T = A)来做到这一点,据我所知,这些变量在某种程度上绑定到实例.也许您可以更详细地说明您的具体情况?

I can't think of any way you may enforce that restriction the way you want. I suggest you try to do that with type variables (i.e. defining a type variable type T = A in class E), which have, as far as I know, some degree of binding to instances. Perhaps you can explain in more detail your specific situation?

这篇关于Scala 中的 F 有界多态性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆