Kotlin:为了Comparable而去掉Unchecked cast

我刚刚实施了选择排序来熟悉Kotlin,并碰上了一个我觉得难以摆脱的不受控制的演员。 该实现基于kotlin.Comparable接口:

 object SelectionSort { fun <T> sort(a: Array<Comparable<T>>) { val N = a.size for(i in 0..N - 2) { var min = i for(j in i + 1..N - 1) { if(less(a[j], a[min])) { min = j } } exchange(a, i, min) } } private fun <T> exchange(a: Array<Comparable<T>>, i: Int, min: Int) { val temp = a[i] a[i] = a[min] a[min] = temp } private fun <T> less(comparable: Comparable<T>, comparable1: Comparable<T>): Boolean { return comparable < (comparable1 as T) // Here is the unchecked cast } } 

确切的消息是“ 未检查铸: Comparable<T> T ”。

我的首选是使用kotlin.Comparable接口作为sort方法的主要参数以及辅助方法。 但是如何以一种干净的方式比较泛型和另一种? 如果这是不可能的,那么使用接口实现类似选择排序的干净选择是什么?

基于这个答案 ,我重新编写了我的选择排序实现:

 object SelectionSort { fun <T : Comparable<T>> sort(a: Array<T>) { val N = a.size for (i in 0..N - 2) { var min = i for (j in i + 1..N - 1) { if (less(a[j], a[min])) { min = j } } exchange(a, i, min) } } fun <T> exchange(a: Array<T>, i: Int, min: Int) { val temp = a[i] a[i] = a[min] a[min] = temp } fun <T : Comparable<T>> less(c1: T, c2: T) = c1 < c2 } 

这个实现现在没有警告。

你应该使用一个绑定<T : Comparable<T>>sortless

 fun <T : Comparable<T>> sort(arr: Array<T>) = ... fun <T : Comparable<T>> less(l: T, r: T) = ... 

没有理由诉诸通常的类型,当它工作得很好没有。

另外,要sort的参数不应该是 Array<Comparable<T>> 。 Kotlin中的数组是不变的 :如果A extends B ,则Array<A>不是Array<B>的子类型。 这不同于Java,其中数组是协变的,而String[]Object[]的子类型。 不变性是正确的方法。 如果你现在定义了排序,你将无法写入

 val arr: Array<String> = ... sort(arr); 

因为sort一个Array<Comparable<String>>但是arr是一个Array<String>

另外,没有理由在exchange加上额外的限制

 fun <T> exchange(arr: Array<T>, i: Int, j: Int) = ... 

解决您的问题,但太复杂

这解决了你的问题:

 inline fun <reified T> less(c1: Comparable<T>, c2: Comparable<T>) = if (c2 is T) { c1 < c2 } else { throw IllegalStateException() // whatever } 

如果您首先检查其类型T则不需要演员T 。 如果T被通用化 ,也就是说你可以在运行时访问它(默认情况下通用类型在运行时不可用),这是可能的。 如果你的methodinline这也是唯一可能的。 请注意,在类型检查之后访问c2可能没有显式的转换,因为编译器已经知道你正在做安全的东西,这叫做“ Smart Cast ” 。

这个实现在错误处理方面不是100%正确的,正如你所看到的那样 – 但这取决于你;-)

但是:不要这样做。

更好的方案

我建议你摆脱在你的实现中处理Comparable ,所以sort方法看起来像这样:

  fun <T: Comparable<T>> sort(a: Array<T>) 

这确保只有T可以被排序,实现Comparable ,它是用泛型类型中的:(上限)表示的。 那么你less方法看起来像:

 private fun <T : Comparable<T>> less(comparable: T, comparable1: T): Boolean { return comparable < comparable1 } 

不需要强制转换:-)

(同样适用于exchange