Kotlin smart使用过滤器投射了一对的第二个值

Cor*_* Wu 4 kotlin

我正在尝试编写一个映射String和Int的函数?成对,然后在继续映射之前过滤对中非空的第二个值.

我的代码看起来像这样:

val ids: List<String> = listOf("a", "b", "c")
val ints: Map<String, Int?> = mapOf("a" to 1, "b" to 2, "c" to null)

ids.map { id: String ->
    Pair(id, ints[id])
}.filter { pair -> pair.second != null}.map { pair: Pair<String, Int> ->
    func(id, pair.second)  
}
Run Code Online (Sandbox Code Playgroud)

问题是第二张地图有错误:

Type inference failed: Cannot infer type parameter T in 
                       inline fun <T, R> kotlin.collections.Iterable<T>.map ( transform (T) -> R ): kotlin.collections.List<R>
Run Code Online (Sandbox Code Playgroud)

这看起来是因为编译器不知道聪明地将我Iterable<Pair<String, Int?>>投入到Iterable<Pair<String, Int>>我之后filter.我该怎么做才能解决这个问题?

Kir*_*man 7

Kotlin的智能演员通常不适用于方法边界之外.但是,无论如何,有几种方法可以实现您的目标.

首先,你可以简单地通过使用!!运算符告诉编译器该对的第二个值永远不为null :

ids.map { id: String -> Pair(id, ints[id]) }
        .filter { pair -> pair.second != null }
        .map { pair: Pair<String, Int?> -> func(pair.second!!) }
Run Code Online (Sandbox Code Playgroud)

其次,您可以颠倒filterand 的顺序map并在!!之前应用运算符:

ids.filter { id: String -> ints[id] != null }
        .map { id: String -> id to ints[id]!! } //equivalent to Pair(id, ints[id]!!)
        .map { pair: Pair<String, Int> -> func(pair.second) }
Run Code Online (Sandbox Code Playgroud)

最后,!!通过使用mapNotNull扩展方法在一个步骤中组合过滤和映射,您可以在没有操作员的情况下使其工作:

ids.mapNotNull { id: String -> ints[id]?.let { id to it } }
        .map { pair: Pair<String, Int> -> func(pair.second) }
Run Code Online (Sandbox Code Playgroud)