1.4语法糖:组合类型


#1

实际开发中经常会遇到这样的问题:
1.一个方法同时要求处理Int、Double、String,这时只能说要么用三个方法分别处理,要么将类型设置为Any并检查提传入了错误类型抛出运行时异常。
2.将一些数据排好序并序列化到硬盘,这时要求类型即是Seriazable也是Comparable,这时没办法只能定义成Any,然后检查传入错误类型时抛出运行时异常。
3.一个方法需要处理数字Number类,但不想接收Byte字节类,目前没办法,只能定义成Number,然后再检查发现传入Byte时抛出运行时异常。

期待1.4能引入组合类型来解决这些问题:
1."或"类型, A|B , A类或B类,表现:直接操作只能为相交部分,各自的独有功能需先判断具体类型
2."且"类型, A&B , 既是A类也是B类,表现:能直接操作A和B的全部功能
3."排除"类型, A-B , 属于A类但不允许B类(父子类等),表现:只能直接操作A的全部功能,B的独有功能不可操作


#2

这个应该算是一个重量级功能了,做出来恐怕得叫 2.0 了吧 :star_struck:


#3

我来抬杠了:thinking:

> 复杂语言特性
> 难以学习
> 劝退
> 辣鸡kt没人用

而且从官方人员的历史回复来看 他们根本不想实装这种能够颠覆目前kt类型系统的语言特性(


#4

划掉的那句我同意。

其实楼主说的 2 已经实现了的。1、3 绝大多数人应该用不着,不知道楼主是做什么开发的?


#5

“且” 类型 已经实现了?我是做后端开发,kotlin用于生产差不多有半年了吧


#6

从实际编码上来说,这些情况很常见,和参数默认值一样,都是弥补重载等旧的类型系统的不足,肯定是有改进的必要的。
从复杂度看,它恰好是简化,如果你要接收String或Int类型,用String|Int 来表示你要接收的类型和用Serizable来表示,你觉得哪个会更易懂?
我觉得除了第三条外都应该能接受,第三条有时会违反了里氏替换原则。


#7

可以用泛型实现的,泛型可以指定多个约束


#8

你接受了 String 、Int 为参数,那么你是不是还要在函数内部 when(xxx) is String ; is Int … 举几个实际的例子吧,单纯的用 String|Int 和Serializable比较没什么意义,更何况是不是真的 “很常见”,都是非常可疑的。


#9

1.内部when:它或许无法避免,但是它可以不需要定义多个方法也能精准控制输入类型。
2.常用性:很多类型都有重载方法,无论是jdk,还是kt,通常同名方法如果不被默认参数取代那基本可以被“或”类型取代。举个例子,Number子类的各数值类的加减乘除方法目前只能接收和自己一致类型,很显然我们经常需要跨类型计算比如int+Double-Long。
*当然,目前jdk也有解决方案:编译器自动对基本类型做隐式转换,而kt只做到对字面量数值做隐式转换。其余情况我们不得由调用者手动转换,或者为六大数值类型做不同类型加减乘除的方法,显然是不如“或”类型更加方便和务实,也更加灵活。


#10

内部when不如直接重载或者按照类型对函数命名,一个大函数比几个小函数恐怕没什么优势吧,不仅逻辑上复杂化,还引入了额外的运行时类型判断。

能被默认参数替代的重载确实不是好的实践,不过剩下的重载情况,我觉得也不应该通过类型聚合到一起,反而把函数名区别化会更清晰,例如 writeInt, writeString 之类肯定比 write(Int | String) 更合适。

另外,类型的复杂化,会让更多的开发者陷入困惑。


#11

第二种情况为什么不能定义一个接口继承Seriazable和Comparable?(抓头


#12

jdk中的类会去实现你定义的接口?


#13

好吧,这种情况啊


#14

方法可不可读清不清晰一般来说主要是看注释和代码量以及使用者的掌握度;前两个不用说新语法完胜;第三个则好比集合的lambda表达式方法,不会用时觉得它是洪水猛兽,它毫无可读性,更别提维护性,而等用会了、精了才发现用普通循环才是很难理解作者要表达的意思,多行代码找不到重点、才是没法维护,我想用好了lambda的程序员应该都有这种体会吧?
我们这个新语法拿时间计算举例,假设fun Date.plusHours(arg)方法用于计算n小时候的时间是多少,你看哪种代码量少、可读性高、可维护性强、执行效率高。
方案一:
一个方法处理short、int、long、float、double,代码只有一行:return time + arg.toDouble * 1000 * 3600

方案二:
分五个方法处理,五个方法都有定义而且都要写类似的文档注释
double的处理方法代码为 return time + arg * 1000 * 3600

short方法return plusHoursDouble(arg.toDouble())

int方法return plusHoursDouble(arg.toDouble())

long方法return plusHoursDouble(arg.toDouble())

float方法return plusHoursDouble(arg.toDouble())


#15

这个例子看上去更像是鸭子类型要解决的问题。恰好他们都有 toDouble,如果没有的话,还是要 when… ,那么就不如分开写了。

换个角度,也许你需要的是一个所有有 toDouble 函数的类型

假如,支持下面的泛型约束,那么这个问题就解决了~

fun <T> Date.plusHours(arg: T) where T: { fun toDouble() }{
    return time + arg.toDouble() * 1000 * 3600
}

Scala 有这个特性,我觉得很好,Kotlin 借鉴并且只能在泛型约束处使用的话也应该不会导致滥用吧。


#16

第二个问题本身就用泛型约束就已经可以实现了。


#17

不得不说这个泛型特性牛逼,就是稍微有点长


#18

我觉得单纯是我说的这种情况 where T: { fun toDouble() },Kotlin 设计者没准儿还真能接受,但组合类型,这个估计他们会比较拒绝~当然也是我的猜测啦


#19

嗯,我觉得选择kotlin多少都是因为java语法不争气,十年如一日,所以kotlin我期望的是大刀阔斧


#20

Kotlin 现在主力都在搞跨平台和 Native,语法特性短期内应该不会有太大的变动。


京ICP备16022265号-2 Kotlin China 2017 - 2018
本站由腾讯云提供计算服务