scala - Scala 的类型推断如何与类型边界一起工作?

标签 scala type-inference type-bounds

当类型参数上存在类型边界时,Scala 究竟如何确定要推断的类型?例如:

def onMouseClicked_=[T >: MouseEvent](lambda: T => Unit) = 
  setOnMouseClicked(new EventHandler[T] {
    override def handle(event: T): Unit = lambda(event)
  })

尝试使用此功能时,例如:
onMouseClicked = { me => doSomething() }
me将具有 MouseEvent 的推断类型. T 的类型界限是一个下界,所以 T必须是 MouseEvent 类型或 MouseEvent 的父类(super class)型, 那为什么 me推断类型为 MouseEvent ?它不应该推断出最普​​遍的类型吗?

关于 Scala 的类型推断是如何工作的,这是我没有得到的东西吗?还是我对类型边界的理解完全错误?

编辑:

假设我们进一步将 T 的类型限制为 Event 的子类型, 其中 EventMouseEvent 的父类(super class)型.所以我们得到:
def onMouseClicked_=[T >: MouseEvent <: Event](lambda: T => Unit) = 
  setOnMouseClicked(new EventHandler[T] {
    override def handle(event: T): Unit = lambda(event)
  })

所以如果我们这样做
onMouseClicked = { me: MouseDragEvent => doSomething() }

在哪里 MouseDragEventMouseEvent 的子类型,编译失败并出现类型错误,正如预期的那样,因为边界确保 me必须是 MouseEvent 的父类(super class)型.

然而,如果我们这样做
onMouseClicked = { me: Any => doSomething() }

编译成功。很明显 Any不是 Event 的子类型,那为什么编译会成功呢? T 的推断类型是什么?

最佳答案

我会试一试,但我不确定一切都会 super 正确或清楚。
前提
要解决的第一点是 T 类型的函数结果R ( T => R ) 的返回类型是协变的,其参数是逆变的:即 Function[-T, +R] .
简而言之,这意味着函数 fsub成为函数的子类型 f它的返回类型必须是相同类型或R的子类型(covariant) 和它的参数必须是相同的或者是 T 的父类(super class)型(逆变)。
让我们试着理解这一点:如果你想能够使用 fsub在哪里 f预计(见 Liskov),你需要一个 fsub最多可以处理 T 的传递参数,但没有更具体的,因为这就是 f 的调用者预计将传递给它。此外,由于 T将被传递,您可以对 fsub 的参数更加宽松并处理其父类(super class)型之一,因为每个 T传递给它的也是它的父类(super class)型的一个实例。
这就是当我们说函数的参数在其类型上是逆变的时的意思:它告诉你它的类型如何在关系子类型中改变函数作为一个整体,或者实际上相反。

鉴于此,让我们回到具体案例。处理程序的 mutator ( onMouseClicked_= ) 至少应该接受 MouseEvent => Unit 类型的 lambda .给它起个名字吧,handler: MouseEvent => Unit .
但这并没有结束,您应该期望能够将这个 lambda 的子类型传递给方法,这个“子函数”的类型是什么?正如我们之前所说,它可以接受 MouseEvent或它的任何父类(super class)型,然后 subhandler: T => UnitT :> MouseEvent .
这正是您所看到的方法的一般形式。
结论
我希望现在很清楚该方法定义 T 的原因作为 MouseEvent 的(非严格)父类(super class)型不是因为您的处理程序将收到任何不同于 MouseEvent 的内容,但是因为您可以传递一个 lambda,它只能处理更抽象的事件类型...(例如,您可以使用 me: Any => doSomething() )

关于scala - Scala 的类型推断如何与类型边界一起工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29966673/

相关文章:

scala - 为什么在嵌套类型参数时 Scala 不能完全推断类型参数?

c++ - 为什么此模板参数推断失败?

generics - 如何在 Rust 中添加一个泛型类型实现另一个泛型类型的约束?

scala - 如果 bound 是抽象类型成员,则具有上限的更高种类的类型构造函数不起作用

scala - 类型推断器如何在 reduceLeft 上工作?

scala - Akka actor并发问题

scala - 无法解析符号 "Scalatest"

scala - 将元素添加到 scala.collection.mutable.Map 的语法是什么?

go - go 'Template.Execute'如何读取其匿名结构的参数字段?

c# - .NET:静态方法的推断泛型类型