TL; DR: Проверьте эту игровую площадку .
Это сорт , возможный с помощью контрактов Kotlin - экспериментальная функция Kotlin 1.3 для улучшения поддержки Smart Cast.
Вот один простой пример contract
:
@ExperimentalContracts
fun Object?.isNotNull(): Boolean {
contract {
// If I return "true", then it means that I am not null
returns(true) implies (this@isNotNull != null)
}
return this != null
}
if (obj.isNotNull())
print(obj.value) // smart-cast applied.
Теперь я говорю вроде , потому что использование контракта имеет некоторые ограничения. Их поддерживают только функции верхнего уровня. Это означает, что вам нужно создать расширение класса Object
.
Другое ограничение заключается в том, что здесь мы хотим проверить обнуляемость Object.value
, а не Object
. Это не поддерживается в определении контракта. Поэтому, хотя это и кажется идеальным, следующее не компилируется:
@ExperimentalContracts
fun Object.doesNotContainNull(): Boolean {
contract {
// The following line gives an error:
// Error in contract description: only references to parameters are allowed in contract description.
returns(true) implies (this@doesNotContainNull.value != null) }
return value != null
}
Как показывает ошибка, мы можем ссылаться на параметры в описании контракта. Таким образом, мы можем найти обходной путь, где мы передаем value
в качестве параметра. В итоге функция будет выглядеть следующим образом:
@ExperimentalContracts
fun Object.doesNotContainNull(value: Int?): Boolean {
contract {
returns(true) implies (value != null)
}
return value != null
}
if (obj.doesNotContainNull(obj.value)) {
passNonNullableValue(obj.value) // smart cast applied!
}
Несмотря на то, что этот подход работает, он опасен, потому что вызывающая сторона не всегда может передать obj.value
в качестве аргумента. Поэтому мы бы хотели обеспечить это условие и выдать ошибку времени выполнения, если проверка не удалась.
@ExperimentalContracts
fun Object.doesNotContainNull(value: Int?): Boolean {
contract {
// "If I return true, then it means that $value is not null."
returns(true) implies (value != null)
}
if(value != this.value)
throw IllegalArgumentException("$value must be ${this.value}")
return value != null
}
Полный пример можно сыграть на этой игровой площадке .