scala - 如何描述和修复这个 Scala 类型不匹配错误?

标签 scala type-systems type-mismatch existential-type parameterized-types

下面是我有时会遇到参数化类型的一种情况的具体实例。基本上,我知道有些类型参数是兼容的,但我不知道如何向代码的某些部分证明这一点。

我正在编写一个将 url 映射到处理函数的请求路由器。下面是一些简化的代码。我创建了一个 List[Route]哪里Route基本上是 UrlMatcher, Function对。

class Route[A](matcher: UrlMatcher[A], handler: HandlerFunction[A])

abstract class UrlMatcher[A] {
   def match(url: String): Option[A]   // None if no match

类型参数 A用于匹配器可能从 URL 中提取的“参数”。它们将被传递给处理程序函数。例如,UrlMatcher[Int]看到像“/users/123”这样的 URL 路径可以将 123 传递给 getUser(id: Int)功能。路由器可能看起来像:
val routes = ArrayBuffer[Route[_]]

def callHandler(url: String) {
  for (r <- routes) {
    val args = r.matcher.matchUrl(url)
    if (args.isDefined)
      r.handler(args.get)  // <--- error here
    }

问题是我收到类型不匹配错误,因为我不知道如何告诉它这两种类型是相同的。
type mismatch; found: args.type (with underlying type Option[Any])  
            required: _$1  

我知道我可以重新设计它,以便 Route有一个类似 matchAndCall 的方法,但如果可能的话,我想保持这个逻辑流程。

更新/编辑

我不完全理解存在类型,但我试过这个......
val routes = ArrayBuffer[T forSome { type T }]()

它消除了上面的不匹配错误。但是,我还有另一个插入 ArrayBuffer 的地方。 .
def route[P](matcher: UrlMatcher[P], handler: Handler[P]): AbstractRoute = {
  val route = new Route(matcher, handler)
  otherRoutes.append(route)   // error here  
  route
}

现在的错误是...
type mismatch;  found : Route[P]  required: Route[T forSome { type T }] Note: P <: T
forSome { type T }, but class Route is invariant in type P. You may wish to define 
P as +P instead. (SLS 4.5) 

为什么是 PT 不兼容,因为它们对 T 没有限制?

最佳答案

这是存在类型(通配符类型的 Scala 等价物)是坏事 (TM) 的原因之一,在不执行 Java 互操作时最好避免:编译器不能(或只是不够聪明)通常推断出哪个类型等于哪个,因为它们都消失了......
为了让编译器理解这些类型是相同的,您需要以某种方式为该类型命名。
类型参数是一种可能性:您可以使用理解的内容定义参数化方法,以便在方法内,类型是众所周知的。

def callHandler(url: String) {
  def call[T](r: Route[T]) = {
    val args = r.matcher.matchUrl(url)
    if (args.isDefined) r.handler(args.get)
    // or args.foreach(r.handler)
  }
  for (r <- routes) call(r)
  // or routes.foreach(call)
}
注意:在更简单的情况下,您也可以使用方差来获得 List[Route[Any]] ,并且您的问题消失了,该类型再次众所周知。在这里我不确定您是否可以制作 Route[A]协变。
Existential types主要用于表示 Java 通配符、Java 原始类型和 JVM 的类型 View (反射和东西),尽管 它们比这三种结构更强大 .如果你可以设计一些东西来避免使用它们,你会为自己省去很多痛苦。这有点争议,但至少,它们与类型推断的交互方式存在很多限制,因此必须小心。

关于scala - 如何描述和修复这个 Scala 类型不匹配错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18791712/

相关文章:

scala - 从 Scala 目录中获取文件列表

Java:类型不匹配:无法从 null 转换为 int

c# - 编译时和运行时转换 c#

scala - 对于 Scala,类型删除有什么好处吗?

java - Java 中兼容类型的正式定义(健全性)

excel - 比较不同/单独表列中的值时出现 'Type mismatch' 运行时错误

kotlin - Kotlin中Java8时间对比

scala - 为什么数组需要 ClassTag 而像 List 这样的集合不需要?

VIM 和 Scala -- 缩进问题?

scala - 我可以将对象的实例方法传递给期望在 Scala 中进行回调的方法吗?