fun main() { val set: Set<Int>? set = null val emptySet: Set<Int> = set.orEmpty() }¿No puedo entender por qué, incluso cuando se escribe explícitamente la variable establecida como Establecer <Int>? el compilador considera que en el método de extensión set.orEmpty () set - es una cadena y, en consecuencia, falla con un error:
Kotlin: Tipo de discrepancia: el tipo inferido es String pero se esperaba Set
Pero al declarar e inicializar en una línea, todo sucede correctamente:
fun main() { val set: Set<Int>? = null val emptySet: Set<Int> = set.orEmpty() }El comportamiento que estás observando puede explicarse por la interacción de dos características de Kotlin:
set se reduce a Nothing? como resultado de un smart cast tras la asignación de valor null al mismo. La transmisión inteligente después de una asignación puede ser útil en los casos en que reduce el tipo de variable a un tipo más específico, pero ¿se reduce a Nothing? hace más mal que bien.orEmpty disponibles para un valor de tipo Nothing? , el no genérico String?.orEmpty() se elige debido a la regla específica de resolución de sobrecarga de Kotlin: se prefiere un candidato no genérico a los genéricos.De hecho, este comportamiento puede ser desconcertante, por lo que informé este problema como KT-50661 .
Creo que esto está relacionado con el hecho de que el compilador no es tan inteligente como para deducir que el conjunto de códigos = nulo se ejecutará exactamente una vez; podría ser cero veces o más de una vez.
Si sabe que ejecutará exactamente uno, puede decírselo al compilador usando una característica llamada kotlin.contracts:
import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract @ExperimentalContracts fun main() { val set: Set<Int>? once { set = null } val emptySet: Set<Int> = set.orEmpty() } @ExperimentalContracts fun once(lambda: () -> Unit) { contract { callsInPlace(lambda, InvocationKind.EXACTLY_ONCE) } lambda() }Consulte https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.contracts/