有没有办法过滤掉null Any? Kotlin Map 中的值?

问题描述 投票:0回答:4

我正在尝试考虑一个函数,允许通过应用单个函数进行类型推断,将

Map<String, Any?>
对象视为
Map<String,Any>

我对 Kotlin 中的转换函数还很陌生,并且尝试过地图上的各种

filter
filterValues
filterNot
,如下所示:

val input = mapOf(Pair("first",null))
val filtered: Map<String,Any> = input.filter { it.value!=null }

它也无法与其中任何一个一起编译

input.filterValues { it!=null }
input.filterNot { it.value==null }
input.filterNot { it.value is Nothing }

我似乎能得到的最接近的是应用多个步骤或有一个未经检查的强制转换警告。我本以为将值过滤为

!=null
就足够了。我唯一的另一个想法是这是由于仿制药?

collections kotlin
4个回答
25
投票

过滤器函数返回一个与原始映射具有相同泛型类型的映射。要转换值的类型,您需要映射 Any? 中的值?到任何,通过强制转换。编译器无法知道传递给 filter() 的谓词确保过滤后的映射的所有值都不为空,因此它无法使用类型推断。所以你最好的方法是使用

val filtered: Map<String, Any> = map.filterValues { it != null }.mapValues { it -> it.value as Any }

或者定义一个函数在一次传递中执行过滤和转换,从而能够使用智能转换:

fun filterNotNullValues(map: Map<String, Any?>): Map<String, Any> {
    val result = LinkedHashMap<String, Any>()
    for ((key, value) in map) {
        if (value != null) result[key] = value
    }
    return result
}

16
投票

编译器只是没有执行足够深入的类型分析来推断,例如,

input.filterValues { it != null }
从映射中过滤掉
null
值,因此生成的映射应该具有非空值类型。基本上可以存在在类型和可空性方面具有任意含义的任意谓词。

没有特殊情况的函数可以从 stdlib 中的映射中过滤

null
值(就像用于迭代的
.filterIsInstance<T>()
一样)。因此,最简单的解决方案是应用未经检查的强制转换,从而告诉编译器您确定类型安全不会被违反:

@Suppress("UNCHECKED_CAST")
fun <K, V> Map<K, V?>.filterNotNullValues() = filterValues { it != null } as Map<K, V>

另请参阅:另一个具有类似问题的问题关于

is
检查。


2
投票

这不会产生任何警告

kotlin 1.5.30

listOfNotNull(
        nullableString?.let { "key1" to it },
        nullableString?.let { "key2" to it }
    ).toMap()

0
投票

在某些情况下,根据

Map
的构建方式,您可能可以首先构建
List

val input = mapOf(Pair("first",null))

Pair(a, b)
应用以下项目插入模式:

b ?.let { Pair(a, it) }

并在创建

List
之前过滤
Map
会产生预期的结果:

val input = listOf(null ?.let { Pair("first", it) })
              .filterNotNull()
              .toMap()
© www.soinside.com 2019 - 2024. All rights reserved.