简体   繁体   English

具有可空参数和返回类型的通用方法

[英]Generalize method with nullable arguments and return type

I have a method that converts ByteArray? 我有一个转换ByteArray?的方法ByteArray? to base64 String? 到base64 String? so that if argument was null output will be null as well. 因此,如果参数为null ,则输出也将为null This is its implementation: 这是它的实现:

fun toBase64String(array: ByteArray?): String? = if(array == null) null else 
    Base64.getEncoder().encodeToString(array)

But when I pass in not nullable ByteArray method returns String? 但是当我传入不为null的ByteArray方法时,它返回String? which is expected. 这是预期的。 Is there a way to make it generic so such use case will be possible: 有没有一种使它通用的方法,这样的用例将是可能的:

val base64 = toBase64String(ByteArray(4))

where base64 will be of type String and not String? 其中base64将是String类型而不是String?类型String? since argument was not nullable? 由于论点是不能为空的?

I just started to work with Kotlin and probably don't know language feature that can make this possible. 我刚刚开始与Kotlin一起工作,可能不知道使它成为可能的语言功能。

You can make two overloads, one for nullable ByteArray? 您可以进行两个重载,一个重载可为空的ByteArray? and one for non-null ByteArray : 一个用于非null ByteArray

fun toBase64String(array: ByteArray): String =   
    Base64.getEncoder().encodeToString(array)

@JvmName("toBase64StringNullable")
fun toBase64String(array: ByteArray?): String? = 
    if (array == null) null else toBase64String(array)

We need @JvmName("...") to avoid the declaration clash in the bytecode. 我们需要@JvmName("...")以避免字节码中的声明冲突。 Also, this allows to distinguish the functions in Java. 而且,这允许区分Java中的功能。

Usage: 用法:

val nonNullBytes: ByteArray = TODO()
val nonNullString = toBase64String(nonNullBytes) // the inferred type is String

val nullableBytes: ByteArray? = TODO()
val nullableString = toBase64String(nullableBytes) // the inferred type is String?

When the argument is of the non-null type ByteArray , the compiler will choose the overload that returns a non-null String . 当参数为非null类型ByteArray ,编译器将选择返回非null String的重载。

Probably overloading methods is the best solution for your case, but for the sake of completeness here are two other ways to realise that using only one method (the nullable one): 可能的重载方法是针对您的情况的最佳解决方案,但是出于完整性考虑,这里还有另外两种方法可以实现仅使用一种方法(可为空的方法):

Not-Null-Asserted operator: 非空声明运算符:

val base64: String = toBase64String(ByteArray(4))!!

Evlis operator: Evlis运算符:

val base64: String = toBase64String(ByteArray(4)) ?: "defaultString"

if argument was null output will be null as well 如果参数为null,则输出也将为null

If that is the only thing the function does when it encounters null argument, it's better to declare it accepting non-null values and use safe call to deal with nulls: 如果那是函数遇到null参数时唯一要做的事情,那么最好声明它接受非null值并使用安全调用来处理null:

fun toBase64String(array: ByteArray): String =   
    Base64.getEncoder().encodeToString(array)

val bytes: ByteArray? = ...
val base64 = bytes?.let { toBase64String(it) }
// the same can be written with function reference instead of lambda
val base64 = bytes?.let(::toBase64String)

Here let function is called only when bytes is not null, otherwise the result of the expression is null . 在这里, let函数仅在bytes不为null时被调用,否则表达式的结果为null When called it invokes the lambda function or the function reference specified as its argument, passing ByteArray which is already checked to be non-null to that function. 调用时,它将调用lambda函数或作为其参数指定的函数引用,并将已检查为不为null的ByteArray传递给该函数。

Also it can be more convenient to declare toBase64String as an extension for ByteArray , so it can be invoked with safe call without the helper function let " toBase64String声明为ByteArray的扩展也可以更加方便,因此可以通过安全调用来调用它,而无需使用helper函数let

fun ByteArray.toBase64String(): String =   
    Base64.getEncoder().encodeToString(this)

val bytes: ByteArray? = ...
val base64 = bytes?.toBase64String()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM