关于Kotlin的自动类型转换详解
前言
Kotlin1.4正式版在好早以前就已经发布了。关于那些“看得见”的新特性,比如SAM转换、参数列表末尾的可选逗号什么的,已经有无数文章介绍过了。所以本文打算介绍一些可能是鲜为人知的、Kotlin官方团队偷偷塞进1.4的新特性。
不过单独讲这些东西会显得文章太过单薄,于是我打算把其他相似的东西拉一起凑凑字数。
本文使用的Kotlin版本为Kotlin1.4。
本文要讲的东西
看题目就知道了,Kotlin里自动类型转换(automatictypeconversion)。这里讲的不是「把一个String转成Any,再转成String」这种和子类型有关的东西,当然也不是SmartCast,而是两个不相容的类型之间的转换,比如说Int转成Long,如下文所示。
数值转换
一般地,在Kotlin里我们不能像Java一样直接把一个Int类型的东西赋值给Long类型的变量,因为它们之间并不具有子类型关系。像下面这样会得到一个编译错误:
valint:Int=555 vallong:Long=int//编译错误! println(long)
你需要调用标准库提供给你的那些toXXX函数把数值转换成其他类型的数值。
valint:Int=555 vallong:Long=int.toLong()//OK println(long)
Kotlin官方团队曾经表示过不喜欢隐式(implicit)的东西,关于数值的隐式类型转换也包括在内。这就导致了使用Kotlin在进行一些关于数值方面的操作时,有时候会写出一些看起来无比蛋疼的代码。
Bennyhuo:就是有时候写点儿计算比较多的代码,满篇的toFloattoDouble。
不一般地,我们可以使用@Suppress来搞事:
valint:Int=233 @Suppress("TYPE_MISMATCH") vallong:Long=int println(long)//233
这个代码是可以跑起来的,而且你真的可以从字节码里看到那个把Int转成Long的指令I2L。
不过我不确定Kotlin的其他target是否能这样用,我也不保证这样写完全不会出问题。(这里是关于@Suppress的免责声明,请读者自行脑补)
SAMConversion
SAM转换也是一种自动类型转换。它把一个lambda表达式(具有函数类型)转成某个具体的接口类型。
funinterfaceISome{ funsome() } funuseSome(some:ISome){} useSome{println("some")}
在我的另一篇文章里有更详细的介绍。
如果读者不同意这个说法,可以选择跳过本小节内容。
CoerciontoUnit
我们都知道Kotlin的lambda表达式是使用里面最后一个表达式的值来作为lambda的返回值的。比如这样:
valblock={"yeah"}
block的类型是()->String。
然后我们来看看这样的情况:
funtest(block:()->Unit){ println(block()) } test{"yeah"}//输出Unit
相信很多人都熟悉这样的写法。
在某些初学者的眼里这看起来像是把一个()->String类型的lambda传给了需要()->Unit类型的函数。
这就是coerciontounit,一个很久以前就存在的特性,可以理解为编译器自动帮你在lambda表达式的最后加了一行Unit,把本来应该是()->String类型的lambda变成了()->Unit类型。
在Kotlin1.4版本,这个特性得到了进化,你甚至可以这样写:
funtest(block:()->Unit){ println(block()) } funsome():String{ return"str" } //需要Kotlin1.4版本 test(::some)//输出Unit
编译器帮你把()->String类型的函数引用转成了()->Unit。
UnitConversion
警告:这是一项未完成的特性!
添加编译器参数-XXLanguage:+UnitConversion,你就开启了一个Kotlin官方团队偷偷塞进1.4版本的未完成的新特性。
这个特性允许你写出这样的代码:
funtest(block:()->Unit){ println(block()) } funsome(block:()->String){ test(block)//这里是重点 //如果你不加那个编译器参数,会报错 } funmain(){ some{"str"} //理论上会输出Unit }
在函数some里把一个()->String传给了test函数,可以看出来这个特性其实和coerciontounit是差不多的。
理论上这样的代码运行时会输出Unit,但是目前由于该特性的代码生成没写好,得不到预期的结果。
另外,在开启了这个特性后,()->String并不会成为()->Unit的子类型,它们依然是两个不相容的类型。
SuspendConversion
警告:这是一项未完成的特性!
这是本文要介绍的第二个Kt官方团队偷偷塞进1.4版本的未完成的新特性。
比如说我们有这样的一个函数:
funtest(f:suspend()->Unit){ //dosomethingwithf }
我们可以这样调用它:
test{println("hi")}
但是这样不行:
valf={println("hi")} test(f)//编译错误
编译器会告诉你类型不匹配,f是()->Unit类型,test函数需要suspend()->Unit类型的参数。
当你添加了编译器参数-XXLanguage:+SuspendConversion,就可以让上面的代码通过编译。
也就是说这个特性可以帮你把普通函数类型的值转成suspend函数类型。
当然由于这是未完成的功能,即使可以通过编译,但是跑起来还是会炸。
这个特性或许会在Kotlin1.5版本完工,但请不要抱有期待。
结尾
我并不想讨论「为什么要加这种奇怪的特性」之类的话题。
不可否认的是,在有限的程序员生涯中,这些新特性可能一次也用不上。上面提到的问题也都有相应的workaround,不需要新特性也可以写出等价的代码,就是没有那么优雅罢了(
到此这篇关于关于Kotlin自动类型转换的文章就介绍到这了,更多相关Kotlin自动类型转换内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。