如何在Kotlin中将零赋给泛型Number?

huangapple go评论47阅读模式
英文:

How to assign a zero to genric Number in Kotlin?

问题

我是 Kotlin 新手,尝试编写一个简单的泛型方法,但它无法编译。

inline fun <T : Number> List<T>.firstOrZero(): T {
    if (isEmpty())
        return 0   // 这行无法编译
    else
        return this[0]
}

有没有办法解决这个问题?

英文:

I'm new to Kotlin, and I'm trying to write a simple generic method but it doesn't compile

inline fun &lt;T:Number&gt; List&lt;T&gt;.firstOrZero() : T {
    if (isEmpty())
        return 0   // this line doesn&#39;t compile
    else
        return this[0]
}

Is there a way to do it?

答案1

得分: 2

你需要为你想要支持的每个Number子类处理它。例如像这样:

inline fun <reified T : Number> List<T>.firstOrZero(): T {
    return (if (isEmpty()) when (T::class) {
        Int::class -> 0
        Double::class -> 0.0
        Float::class -> 0f
        BigInteger::class -> BigInteger.ZERO
        else -> throw RuntimeException()
    }
    else
        this[0]) as T
}
英文:

You will need to handle it for every single Number subclass you want to support. For example like this

inline fun &lt;reified T : Number&gt; List&lt;T&gt;.firstOrZero(): T {
    return (if (isEmpty()) when (T::class) {
        Int::class -&gt; 0
        Double::class -&gt; 0.0
        Float::class -&gt; 0f
        BigInteger::class -&gt; BigInteger.ZERO
        else -&gt; throw RuntimeException()
    }
    else
        this[0]) as T
}

答案2

得分: 1

我们不能以一种完全通用的方式在 Kotlin 中处理这种情况。无论我们选择什么解决方案,都必须分别处理每种类型的 Number

因此,我建议不要使用通用函数,而是使用多个重载:

fun List<Int>.firstOrZero() = if (isEmpty()) 0 else this[0]
fun List<Long>.firstOrZero() = if (isEmpty()) 0 else this[0]

这应该比使用反射的通用解决方案潜在地更快,因为类型在编译时而不是运行时解析。

如果您有更多类似的情况,您的情况更复杂等,而且您担心代码重复,您可以内联公共代码:

fun List<Int>.firstOrZero() = firstOrDefault { 0 }
fun List<Long>.firstOrZero() = firstOrDefault { 0 }

private inline fun <T:Number> List<T>.firstOrDefault(default: () -> T) : T {
    if (isEmpty())
        return default()
    else
        return this[0]
}

但对于特定的 firstOrZero() 情况,我认为这有点过于复杂。

英文:

We can't really handle this case in a fully generic way in Kotlin. Whatever solution we choose, we have to handle each type of Number separately.

Therefore, I suggest to not go with a generic function, but with multiple overloads:

fun List&lt;Int&gt;.firstOrZero() = if (isEmpty()) 0 else this[0]
fun List&lt;Long&gt;.firstOrZero() = if (isEmpty()) 0 else this[0]

This should be potentially faster than generic solutions using reflection, because the type is resolved at the compile time instead of runtime.

If you have more cases like this, your cases are more complicated, etc. and you are concerned about the code duplication, you can inline the common code:

fun List&lt;Int&gt;.firstOrZero() = firstOrDefault { 0 }
fun List&lt;Long&gt;.firstOrZero() = firstOrDefault { 0 }

private inline fun &lt;T:Number&gt; List&lt;T&gt;.firstOrDefault(default: () -&gt; T) : T {
    if (isEmpty())
        return default()
    else
        return this[0]
}

But for the specific case of firstOrZero() I think it is an overkill.

答案3

得分: -3

你需要确保返回类型与预期类型匹配。

因为你定义了泛型类型'T',所以需要返回'T',它是'Number'的子类型。

英文:

You need to ensure that the return type matches the expected type.

Because you defined the generic type 'T', you need to return 'T', which extends 'Number'.

inline fun &lt;T : Number&gt; List&lt;T&gt;.firstOrZero(): T {
    if (isEmpty())
        return 0 as T
    else
        return this[0]
}

答案4

得分: -4

有一种方法可以做到这一点。您可以使用默认关键字为 T 类型参数提供默认值。在这种情况下,默认值将为 0。以下代码将编译并运行:

inline fun <T:Number> List<T>.firstOrZero() : T {
    if (isEmpty())
        return 0.default<T>()   // 此行编译
    else
        return this[0]
}

默认关键字可用于为任何类型参数提供默认值。当您希望确保方法或属性始终具有值时,即使未指定类型参数时,这很有用。

在此示例中,使用默认关键字为 T 类型参数提供了默认值 0。这意味着如果未指定 T 类型参数,该方法将返回 0。

以下是如何使用 firstOrZero() 方法的示例:

val list = listOf(1, 2, 3)
val firstNumber = list.firstOrZero()
println(firstNumber) // 打印 1

val emptyList = emptyList<Int>()
val firstNumberInEmptyList = emptyList.firstOrZero()
println(firstNumberInEmptyList) // 打印 0
英文:

There is a way to do it. You can use the default keyword to provide a default value for the T type parameter. In this case, the default value will be 0. The following code will compile and run:

inline fun &lt;T:Number&gt; List&lt;T&gt;.firstOrZero() : T {
    if (isEmpty())
        return 0.default&lt;T&gt;()   // this line compiles
    else
        return this[0]
}

The default keyword can be used to provide a default value for any type parameter. This can be useful when you want to make sure that a method or property always has a value, even if the type parameter is not specified.

In this case, the default keyword is used to provide a default value of 0 for the T type parameter. This means that if the T type parameter is not specified, the method will return 0.

Here is an example of how to use the firstOrZero() method:

val list = listOf(1, 2, 3)
val firstNumber = list.firstOrZero()
println(firstNumber) // prints 1

val emptyList = emptyList&lt;Int&gt;()
val firstNumberInEmptyList = emptyList.firstOrZero()
println(firstNumberInEmptyList) // prints 0

huangapple
  • 本文由 发表于 2023年6月12日 14:43:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/76454147.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定