Я пытаюсь узнать больше о расширениях и дженериках абстрактного класса Kotlin, создав очень простые методы и свойства getters, которые расширяют встроенные классы. Я в основном был успешным, но меня превзошел класс Number. Мое свойство test Number.sgn
предназначено для возврата знака (1 или -1 как Int) любого подкласса Number. Для простоты отрицательные должны возвращать -1, а положительные числа и 0 должны возвращаться 1. Я не особо интересуюсь прецедентом этого метода, но для понимания того, как писать что-то простое – и почему мой код генерирует ошибка. Единственный импорт в моем модуле – kotlin.text.*
И сообщение об ошибке, которое я получаю, ссылается на конфликт там. Я просто не понимаю, почему он конфликтует и как его преодолевать, хотя я предполагаю, что это новичок.
Сначала я написал код для расширения класса Int, который отлично работает:
inline val Int.sgn get() = if (this<0) -1 else 1 // sign of number
Затем я попытался обобщить и перенести его в класс Number, например:
inline val Number.sgn get() = if (this<0) -1 else 1 // doesn't compile
и ошибка компиляции выглядит следующим образом:
unresolved reference. None of the following candidates is applicable because of receiver type mismatch: public fun String.compareTo(other: String, ignoreCase: Boolean = ...): Int defined in kotlin.text inline fun Number.sgn() = if (this<0) -1 else 1 ^
Затем я попробовал другой подход, используя дженерики:
inline val <T:Number> T.sgn get() = if (this<0) -1 else 1
и я получил ту же ошибку от компилятора:
error: unresolved reference. None of the following candidates is applicable because of receiver type mismatch: public fun String.compareTo(other: String, ignoreCase: Boolean = ...): Int defined in kotlin.text inline val <T:Number> T.sgn get() = if (this<0) -1 else 1 ^
Может ли кто-нибудь помочь мне понять, почему существует несоответствие типа, и почему здесь имеет значение kotlin.text
? Есть ли подход, который я мог бы использовать для преодоления этой проблемы и получить этот атрибут getter для всех подклассов Number? (Опять же, я знаю, что это не значимый вариант использования, а упрощенный пример, чтобы помочь мне понять принципы, лежащие в основе этого.) Спасибо заранее за любые советы, которые каждый может дать …
Ваша первая функция работает, потому что Int
реализует Comparable<Int>
, это то, на что переводется оператор <
. Однако, если вы посмотрите на класс Number
, вы увидите, что он имеет в нем только функции для конверсий по своим различным подклассам – он не реализует Comparable
, поэтому вы не можете использовать оператор <
на нем.
Вместо этого вы можете сначала преобразовать свой Number
в Double
, а затем посмотреть, является ли он отрицательным:
inline val <T : Number> T.sgn get() = if (this.toDouble() < 0) -1 else 1
Вы также можете сделать свой исходный код (с или без дженериков), compareTo
функцию compareTo
для Number
в качестве расширения:
operator fun Number.compareTo(other: Number) = this.toDouble().compareTo(other.toDouble())
Просто имейте в виду, что отбрасывание всего на Double
может привести к потере точности.