在下面的代码中:
val sum = listOf(1, 2, 3).sumOf { if (it % 2 == 0) 1 else 0 }
Run Code Online (Sandbox Code Playgroud)
Kotlin 给出以下错误:
Kotlin: Overload resolution ambiguity:
public inline fun <T> Iterable<TypeVariable(T)>.sumOf(selector: (TypeVariable(T)) -> Int): Int defined in kotlin.collections
public inline fun <T> Iterable<TypeVariable(T)>.sumOf(selector: (TypeVariable(T)) -> Long): Long defined in kotlin.collections
Run Code Online (Sandbox Code Playgroud)
如果我明确使用toInt(),错误就会消失,但我会收到冗余调用的警告
Kotlin: Overload resolution ambiguity:
public inline fun <T> Iterable<TypeVariable(T)>.sumOf(selector: (TypeVariable(T)) -> Int): Int defined in kotlin.collections
public inline fun <T> Iterable<TypeVariable(T)>.sumOf(selector: (TypeVariable(T)) -> Long): Long defined in kotlin.collections
Run Code Online (Sandbox Code Playgroud)
为什么 Kotlin 不在Int这里自动使用?
该规范对整数文字的类型进行了以下规定:
\n\n\n不带标记的文字具有特殊的整数文字类型\n取决于文字的值:
\n\n
\n- 如果该值大于最大值
\nkotlin.Long,则它是非法整数文字,应该是编译时错误;- 否则,如果该值大于最大值
\nkotlin.Int,则其类型为kotlin.Long;- 否则,它具有一个整数文字类型,其中包含保证能够表示该值的所有内置整数类型。
\n
因此,像“1”这样的整数文字没有像kotlin.Intor这样的简单类型kotlin.Long。它有一个“整数文字类型”。
\n\n示例:整数文字的
\n0x01值为 1,因此类型为ILT(kotlin.Byte,kotlin.Short,kotlin.Int,kotlin.Long)。整数文字 70000 的值为 70000,无法使用类型表示kotlin.Byte,kotlin.Short因此具有 typeILT(kotlin.Int,kotlin.Long)。
以下是这些 ILT 的子类型规则。对于你的问题重要的是:
\n\xe2\x88\x80Ti\xe2\x88\x88{T1,\xe2\x80\xa6,TK}:ILT(T1,\xe2\x80\xa6,TK)<:Ti\nRun Code Online (Sandbox Code Playgroud)\n\xe2\x80\x8b
\n这条规则基本上表明 ILT 的工作方式类似于交集类型。例如,ILT(kotlin.Int,kotlin.Long)是 的子类型kotlin.Int,也是 的子类型kotlin.Long。
现在让我们看看你的 lambda { if (it % 2 == 0) 1 else 0 }。它返回文字 0 或文字 1。它们都具有以下类型:
ILT(kotlin.Byte,kotlin.Short,kotlin.Int,kotlin.Long)\nRun Code Online (Sandbox Code Playgroud)\nkotlin.Long这是和的子类型kotlin.Int。因此,您的 lambda 可以转换为 a(T) -> Long和 a (T) -> Int,就像 a(T) -> Dog可以转换为 a一样(T) -> Animal一样。
当您使用 时toInt(),只有(T) -> Int重载与返回类型匹配,因为Int不能Long隐式转换为。
显然,如果你toInt()对整个表达式执行此操作,则不会出现多余的toInt警告:
fun main() {\n val sum = listOf(1, 2, 3).sumOf { (if (it % 2 == 0) 1 else 0).toInt() }\n}\nRun Code Online (Sandbox Code Playgroud)\nsumOf另请注意,编译器仅因为用 注释而查看 lambda 返回类型OverloadResolutionByLambdaReturnType。如果不是这样,即使您使用toInt(). 有关详细信息,请参阅使用 lambda 返回类型来优化函数适用性。
它能够在简单情况下选择重载的原因Int如下:
fun foo(x: Int) {}\nfun foo(x: Long) {}\nfun main() { foo(43) }\nRun Code Online (Sandbox Code Playgroud)\n是因为重载决策中的“选择最具体的候选者”步骤。在此步骤中,它以不同的方式处理内置数字类型,并考虑Int“最具体”。然而,这一步发生在“使用 lambda 返回类型来优化函数适用性”之前,并且认为(T) -> Int和(T) -> Long是同样具体的。
| 归档时间: |
|
| 查看次数: |
223 次 |
| 最近记录: |