规范中对这types of integer literals辆车作了如下说明:
没有标记的文字具有特殊的整数文字类型
- 如果该值大于最大值
kotlin.Long
,则为非法整数文字,应为编译时错误;
- 否则,如果该值大于最大值
kotlin.Int
,则其具有类型kotlin.Long
;
- 否则,它有一个integer literal type,其中包含保证能够表示该值的所有内置整数类型.
所以像"1"这样的整数文字没有像kotlin.Int
或kotlin.Long
这样的简单类型.它有一个"整数文字类型".
示例:整数文字0x01
的值为1,因此具有类型ILT(kotlin.Byte,kotlin.Short,kotlin.Int,kotlin.Long)
.整数文字70000的值为70000,不能使用类型kotlin.Byte
和kotlin.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.Long
和kotlin.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返回类型,因为sumOf
用OverloadResolutionByLambdaReturnType
注释.如果不是这样,即使使用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
同样具体.