如果参数不为空,我如何告诉 kotlin 函数不返回空值?

Grz*_*icz 7 android static-analysis nullable kotlin

我想编写一个方便的扩展来从 Map 中提取值,同时解析它们。如果解析失败,函数应该返回一个默认值。这一切正常,但我想告诉 Kotlin 编译器,当默认值不为空时,结果也不会为空。我可以通过@Contract注释在 Java 中做到这一点,但它似乎在 Kotlin 中不起作用。这能做到吗?合同不适用于扩展功能吗?这是 kotlin 尝试:

import org.jetbrains.annotations.Contract

private const val TAG = "ParseExtensions"

@Contract("_, !null -> !null")
fun Map<String, String>.optLong(key: String, default: Long?): Long? {
    val value = get(key)
    value ?: return default

    return try {
        java.lang.Long.valueOf(value)
    } catch (e: NumberFormatException) {
        Log.e(TAG, e)
        Log.d(TAG, "Couldn't convert $value to long for key $key")

        default
    }
}

fun test() {
    val a = HashMap<String, String>()

    val something: Long = a.optLong("somekey", 1)
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,something尽管optLong使用非空的默认值 1 调用,IDE 仍会突出显示分配中的错误。 为了比较,这里是通过 Java 中的注释和契约测试可空性的类似代码:

public class StackoverflowQuestion
{
    @Contract("_, !null -> !null")
    static @Nullable Long getLong(@NonNull String key, @Nullable Long def)
    {
        // Just for testing, no real code here.
        return 0L;
    }

    static void testNull(@NonNull Long value) {
    }

    static void test()
    {
        final Long something = getLong("somekey", 1L);
        testNull(something);
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码没有显示任何错误。只有当@Contract注释被删除时,IDE 才会警告调用testNull()可能为空值的 。

Aro*_*Aro 3

您可以通过使函数通用来做到这一点。

fun <T: Long?> Map<String, String>.optLong(key: String, default: T): T 
{
    // do something.
    return default
}
Run Code Online (Sandbox Code Playgroud)

可以像这样使用:

fun main(args: Array<String>) {
    val nullable: Long? = 0L
    val notNullable: Long = 0L

    someMap.optLong(nullable) // Returns type `Long?`
    someMap.optLong(notNullable) // Returns type `Long`
}
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为它Long?是一个超类型Long。通常会推断类型,以便根据参数返回可为空或不可为空的类型。

这将“告诉 Kotlin 编译器,当默认值不为 null 时,结果也不会为 null”。