在以下代码中:

val sum = listOf(1, 2, 3).sumOf { if (it % 2 == 0) 1 else 0 }

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

Playground

如果显式使用toInt(),则错误消失,但会收到冗余调用的警告

val sum = listOf(1, 2, 3).sumOf { if (it % 2 == 0) 1.toInt() else 0 }

为什么Kotlin在这里不自动使用Int

推荐答案

规范中对这types of integer literals辆车作了如下说明:

没有标记的文字具有特殊的整数文字类型

  • 如果该值大于最大值kotlin.Long,则为非法整数文字,应为编译时错误;
  • 否则,如果该值大于最大值kotlin.Int,则其具有类型kotlin.Long
  • 否则,它有一个integer literal type,其中包含保证能够表示该值的所有内置整数类型.

所以像"1"这样的整数文字没有像kotlin.Intkotlin.Long这样的简单类型.它有一个"整数文字类型".

示例:整数文字0x01的值为1,因此具有类型ILT(kotlin.Byte,kotlin.Short,kotlin.Int,kotlin.Long).整数文字70000的值为70000,不能使用类型kotlin.Bytekotlin.Short表示,因此具有类型ILT(kotlin.Int,kotlin.Long).

这是subtyping rules个ILT.对于您的问题,重要的是:

∀Ti∈{T1,…,TK}:ILT(T1,…,TK)<:Ti


This rule basically says that ILTs work like an intersection type. For example, ILT(kotlin.Int,kotlin.Long) is a subtype of kotlin.Int and also a subtype of kotlin.Long.

现在让我们看看你的lambda { if (it % 2 == 0) 1 else 0 }.它返回文字0或文字1.它们都有以下类型:

ILT(kotlin.Byte,kotlin.Short,kotlin.Int,kotlin.Long)

它是kotlin.Longkotlin.Int的一个子类型.因此,您的lambda可以转换为(T) -> Long(T) -> Int,就像(T) -> Dog可以转换为(T) -> Animal一样.

使用toInt()时,只有(T) -> Int重载与返回类型匹配,因为Int不能隐式转换为Long.

显然,如果在整个表达式上执行toInt(),则没有多余的toInt警告:

fun main() {
    val sum = listOf(1, 2, 3).sumOf { (if (it % 2 == 0) 1 else 0).toInt() }
}

还请注意,编译器只会查看lambda返回类型,因为sumOfOverloadResolutionByLambdaReturnType注释.如果不是这样,即使使用toInt(),您仍然会得到模糊错误.更多信息请参见Using lambda return type to refine function applicability.

它能够在以下简单情况下 Select Int过载的原因:

fun foo(x: Int) {}
fun foo(x: Long) {}
fun main() { foo(43) }

是因为过载分辨率中的"Choosing the most specific candidate"步.在这一步中,它以不同的方式处理内置的数字类型,并认为Int是"最具体的".然而,该步骤发生在"使用lambda返回类型来细化函数适用性"之前,并且认为(T) -> Int(T) -> Long同样具体.

Kotlin相关问答推荐

在Mapstruct中重用@映射定义

在Webflux应用程序中通过kotlin协程启动fire and forget job

为什么会出现Kotlin.Unit错误以及如何修复它?

如何获取@JsonProperty 名称列表?

Kotlin 可空泛型

第二个协程永远不会执行

将 Gradle 子元素与 Kotlin 多平台一起使用

模拟异常 - 没有找到答案

如何在 Kotlin 中使用 volatile

在 Scaffold Jetpack Compose 内的特定屏幕上隐藏顶部和底部导航器

Kotlin 类的调用方法

Foo::class.java 和 Foo::javaClass 有什么区别?

kotlin:扩展方法和空接收器

Kotlin的web-framework框架

Kotlin-通过与属性列表进行比较来筛选对象列表

如何捕获传递给模拟函数的参数并返回它?

Kotlin:如何从另一个类访问字段?

在 Kotlin 函数上使用 Mokito anyObject() 时,指定为非 null 的参数为 null

Kotlin中的函数接口

Kotlin - 错误:Could not find or load main class _DefaultPackage