为什么 Kotlin 类型推断不适用于函数式接口?

Why Kotlin type inference does not work for functional interface?

我正在为 http 处理程序和过滤器(又名拦截器)开发 http4k web app. Http4k has a nice functional scheme

typealias HttpHandler = (Request) -> Response

interface Filter : (HttpHandler) -> HttpHandler {...}

我想写一个简单的过滤器,所以我创建了一个函数 returns a Filter

fun throwNotFoundResponses(): Filter {
    return { next: HttpHandler ->
        { request: Request ->
            val response = next(request)
            if (response.status == Status.NOT_FOUND) {
                throw NotFoundException()
            }
            response
        }
    }
}

// example usage
Filter.NoOp
        .then(throwNotFoundResponses())
        .then(routes(...))

但是 Kotlin 抱怨(编辑行号以匹配上面的示例。)

NotFoundThrower.kt: (2, 12): Type mismatch: inferred type is (HttpHandler /* = (Request) -> Response */) -> (Request) -> Response but Filter was expected

为什么 Kotlin 不能推断类型实际上是相同的?

你可以使用Filter() ~constructor~ 重载运算符函数invoke并为其提供过滤函数:

fun throwNotFoundResponses(): Filter {
    return Filter { next: HttpHandler ->
        { request: Request ->
            val response = next(request)
            if (response.status == Status.NOT_FOUND) {
                throw NotFoundException()
            }
            response
        }
    }
}

或更简洁:

fun throwNotFoundResponses(): Filter = Filter { next: HttpHandler ->
    { request: Request ->
        next(request).takeIf { it.status != Status.NOT_FOUND } 
            ?: throw NotFoundException()
    }
}

Filter 是扩展 (HttpHandler) -> HttpHandler 的接口,因此它是它的子类,而不是超类。

如果你没有函数式语法,也许更容易看出来。

open class Animal
class Kitten: Animal()

fun doSomething(): Kitten {
    // You cannot return an explicit Animal here, even though the Kitten implementation
    // has not defined any unique members or overridden anything. 
}

你的 lambda 实际上是一个 (HttpHandler) -> HttpHandler 并且不能被推断为一个过滤器,就像一个任意的动物可以被投射到一只小猫一样。我们没有碰巧向 Kitten 添加任何功能或覆盖任何东西都没有关系。这仅仅是声明意味着它是一个独特的子类型,编译器永远不会假设。