kotlin 为什么Comparator中有“in”关键字

eit6fx6z  于 2023-03-24  发布在  Kotlin
关注(0)|答案(2)|浏览(167)

这是实现binarySearch方法的Kotlin代码:

public fun <T> List<T>.binarySearch(element: T, comparator: Comparator<in T>, fromIndex: Int = 0, toIndex: Int = size): Int {
rangeCheck(size, fromIndex, toIndex)

var low = fromIndex
var high = toIndex - 1

while (low <= high) {
    val mid = (low + high).ushr(1) // safe from overflows
    val midVal = get(mid)
    val cmp = comparator.compare(midVal, element)

    if (cmp < 0)
        low = mid + 1
    else if (cmp > 0)
        high = mid - 1
    else
        return mid // key found
}
return -(low + 1)  // key not found
}

为什么Comparator的类型为而不是T?
我们使用in仅仅是为了可读性吗?或者在上面的代码片段中有一个实际的用途,如果我们不使用“in”,事情就不会工作?

ttcibm8c

ttcibm8c1#

使用Comparator而不是Comparator允许方法接受在T的超类型上操作的Comparator。
这很有用,因为它使binarySearch方法更加灵活,并且可以处理列表中的元素是搜索元素类型的子类型的情况。例如,如果T是Animal,并且列表包含Dog和Cat对象,则即使搜索元素是Dog或Cat,该方法仍可以使用对Animal对象进行操作的Comparator。
如果我们使用Comparator,binarySearch方法将只接受专门对T对象进行操作的Comparator,这将限制其灵活性。
因此,在这种情况下,in关键字不仅仅用于可读性目的,它确保方法可以接受在T的超类型上操作的Comparator。

idfiyjo8

idfiyjo82#

从理论上讲,它可以使系统更灵活。

interface Fruit {
    val englishName: String
}

val fruitNameComparator: Comparator<Fruit> = compareBy { it.englishName }

class Apple: Fruit {
    override val englishName = "Apple"
} 

class Orange: Fruit {
    override val englishName = "Orange"
}

fun main() {
    val orangesList: List<Orange> = listOf(Orange(), Orange())
    val searchResult = orangesList.binarySearch<Orange>(Orange(), fruitNameComparator)

这是因为Comparator<Fruit>Comparator<in Orange>的子类型,但它不是Comparator<Orange>的子类型。
然而,在这个例子中的用处是非常有限的,你可以调用:

orangesList.binarySearch<Fruit>(Orange(), fruitNameComparator)

或者完全省略泛型类型以允许推断它,它会工作得很好,因为您的List<Orange>也是List<Fruit>
如果二进制搜索函数返回找到的实际项,那么它返回T,那么额外的灵活性将更有用,因为T可以解析为Orange而不是Fruit,所以返回的项将是更具体的类型。

相关问题