Коллекции Котлина : Вычитание двух обнуляемых списков дает неверный результат

#kotlin

#котлин

Вопрос:

Использование функции минус в списке, не допускающем обнуления, работает правильно…

 val listA: Listlt;Stringgt; = listOf("1", "2", "3") val listB : Listlt;Stringgt; = listOf("1", "2", "3") assertEquals(0, listB.minus(listA).size) // Test PASSED  

…Но в списке, подлежащем аннулированию, он не работает с оператором безопасного вызова ?. почему?

 val listA: Listlt;Stringgt;? = listOf("1", "2", "3") val listB : Listlt;Stringgt;? = listOf("1", "2", "3") assertEquals(0, listB?.minus(listA)?.size) // Test FAILED  

Комментарии:

1. Вывод имеет значение времени Int?

Ответ №1:

Это «уловка» Котлина, связанная с тем, как они реализовали дисперсию списков и перегрузили minus функцию. На самом деле вы вызываете две разные перегрузки minus функции.

В вашем первом примере вы вызываете перегрузку с помощью этой подписи:

 fun lt;Tgt; Iterablelt;Tgt;.minus(elements: Iterablelt;Tgt;): Listlt;Tgt;  

Он видит a Listlt;Stringgt; с параметром an Iterablelt;Stringgt; ( listB ), поэтому T выводится как a String , и он может удалить элементы из списка и вернуть пустое Listlt;Stringgt; значение .

Во втором примере приведенная выше перегрузка не соответствует, поскольку listB?. означает , что получатель является a Listlt;Stringgt; , но параметр listA не является an Iterablelt;Stringgt; . Это ан Iterablelt;Stringgt;? . Поэтому вместо этого вызывается другая, менее специфичная перегрузка функции:

 fun lt;Tgt; Iterablelt;Tgt;.minus(element: T): Listlt;Tgt;  

Поскольку a Listlt;Stringgt; также является a Listlt;Any?gt; (из-за ковариации), и a Listlt;Stringgt;? квалифицируется как an Any? , функция совпадает с использованием a T of Any? . И поскольку сам экземпляр списка не является элементом в listB возвращаемом списке, в нем не меньше элементов, чем listB было.

При работе со списками, допускающими обнуление orEmpty() , эта функция часто пригодится:

 val listA: Listlt;Stringgt;? = listOf("1", "2", "3") val listB : Listlt;Stringgt;? = listOf("1", "2", "3") assertEquals("nullable", 0, listB.orEmpty().minus(listA.orEmpty()).size) // PASSES  

orEmpty() является сокращением ?: emptyList() , и это гарантирует, что вы работаете со списком, не подлежащим аннулированию. Это также удобно для строк, допускающих обнуление.