Как гарантировать, что дженерик безопасно расширяет определенный класс в Котлине?

Я хотел создать свой собственный класс Map, который допускает только класс Number (т. е. Int, Long, Double, ...). Кроме того, если значение записи станет нулевым, эта запись будет автоматически удалена с карты. Поскольку я не знаком с дженериками в Котлине, имейте в виду, что я, возможно, написал класс правильно, но ниже приведен код, который я написал.

class PositiveMap<K, V> : HashMap<K, V>() where V : Number {
    override fun put(key: K, value: V): V? {
        val isZero = when (value) {
            is Byte -> value == 0.toByte()
            is Short -> value == 0.toShort()
            is Int -> value == 0
            is Long -> value == 0L
            is Float -> value == 0f
            is Double -> value == 0.0
            is BigInteger -> value == BigInteger.ZERO
            is BigDecimal -> value == BigDecimal.ZERO
            else -> false
        }

        // Don't put value at all if value was zero, and there was no such key
        if (!containsKey(key) && isZero) {
            return null
        }

        val old = super.put(key, value)

        // Remove entry if value turned out to be zero
        if (isZero) {
            remove(key)

Однако IDE предупреждает меня, что в каждом случае проверка того, равен ли value нулю, всегда возвращает false.

Я попытался добавить немного грязную проверку, как показано ниже, но IDE предупреждает, что value действительно является Number классом.

Поэтому я просто решил создать код тестового модуля и проверить, работает он нормально или нет.

class TestUnit {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            // Putting PositiveMap<String, String> shows error as intended
            val map = PositiveMap<String, Long>()

            map["hello"] = 1L

            println(map["hello"])
            println(map.containsKey("hello"))

            map["hello"] = (map["hello"] ?: 0L) - 1L

            println(map["hello"])
            println(map.containsKey("hello"))
        }
    }
}

Вывод был как ниже

1
true
null
false

Этот вывод заставил меня почувствовать, что IDE просто показывает ложные срабатывания. Однако, как я уже говорил выше, я не знаком с дженериками, поэтому не могу себя уверить, что это баг IDE.

Я использую IntelliJ IDEA, ниже приведена информация о версии.

и ниже представлена ​​версия Kotlin, которую я использую

Это ложное предупреждение (вероятно, ошибка) или есть ли способ удалить предупреждение, которое выдает IDE?

Обновлено:

Я вместо этого попробовал поставить value <= 0 для каждого случая, тогда предупреждения убираются. Однако я все еще задаюсь вопросом, почему проверка точного нуля предупреждает меня

Скорее всего, это просто ошибка IntelliJ.

Sweeper 10.06.2024 03:46

проблема в том, что компилятор не может выполнять интеллектуальное приведение value в этих ветках. Если вы переключитесь на новый компилятор K2 (который стал стабильным с Kotlin 2.0.0), предупреждение исчезнет.

user2340612 10.06.2024 16:02

Спасибо всем, ребята, как упоминал @user2340612, я попробовал компилятор K2, и он удалил предупреждения! Вы можете написать ответ, чтобы вас приняли, или я напишу ответ сам.

Mandarin Smell 11.06.2024 09:02
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
69
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Похоже, что старая версия компилятора Kotlin (используемая IntelliJ для проверки кода) не способна реализовать, что в этих when ветках переменную value можно безопасно привести к соответствующему типу. Вероятно, это вызвано ограничением существующей версии компилятора и, похоже, исправлено в новом компиляторе K2.

Если вы включите режим K2 в IDE, вы увидите, что переменная value будет автоматически приведена к правильному типу, и соответствующее предупреждение исчезнет.

Обратите внимание: несмотря на то, что компилятор K2 стабилен, IntelliJ IDEA в настоящее время все еще использует старый компилятор для подсветки синтаксиса, проверки и т. д., поскольку «режим K2» все еще находится в альфа-версии — см. здесь. Вы можете включить «режим K2» в IntelliJ 2024.1 (или новее), но имейте в виду, что

Производительность и стабильность подсветки кода и завершения кода были значительно улучшены, но пока поддерживаются не все функции IDE.

Я обнаружил, что сам компилятор Kotlin (то есть командная строка kotlinc) не выдает никаких предупреждений, даже в более ранних версиях. Эти предупреждения выдает только IDE.

k314159 11.06.2024 15:45

правильно. То, что выделяет IDE, является результатом «проверки», поэтому технически это подсказка IDE, а не предупреждение компилятора. Однако IDE использует встроенный компилятор для оценки этих проверок, поэтому фактическое «исправление» этой проблемы состоит в том, чтобы просто включить «режим K2» в IDE. Я обновил свой ответ, чтобы прояснить этот момент.

user2340612 11.06.2024 15:55

Другие вопросы по теме