Тип возвращаемого значения Kotlin Generics совпадает с получателем - PullRequest
0 голосов
/ 30 декабря 2018

Я пытаюсь создать функцию, которая возвращает значение по умолчанию, если получатель имеет нулевое значение для чисел.Однако, когда я проверяю тип полученного значения, оно не совпадает с получателем, вместо этого оно совпадает со значением по умолчанию, которое я передал в качестве аргумента.

fun <T : Number> T?.orDefault(value: T): T = this ?: value

Тестирование вышеупомянутой функции скод ниже:

fun main(args: Array<String>) {
    val b: Double? = null
    val default : Int = -1
    val orDefault = b.orDefault(default)
    println(orDefault)
    println(orDefault.javaClass.name)
}

Вывод выглядит примерно так:

// Output:
-1
java.lang.Integer

Когда я попробовал это, введя еще один J, расширяющий T, это все равно не удается.Запуск с вышеупомянутым основным методом все еще не удается.

fun <T : Number, J : T> T?.orDefault(value: J): T = this ?: (value as T)

// Output:
-1
java.lang.Integer

Ни в одном из случаев он не возвращает double.Что здесь не так?

РЕДАКТИРОВАТЬ :

Я закончил тем, что сделал что-то вроде этого:

fun <T : Number, J : Number> T?.orDefault(value: J): T = this ?: (value as T)

Таким образом, он гарантирует, что возвраттип совпадает с типом получателя.Тем не менее, единственным недостатком является то, что для приемника Null Int он примет Double по умолчанию и приведёт к Int для возврата.

Ответы [ 3 ]

0 голосов
/ 30 декабря 2018

Обобщения не являются оптимальным решением здесь.Так как Number имеет только 7 подклассов, лучше перегрузить вашу функцию расширения следующим образом:

1-й способ:

fun Int?.orDefault(value: Int) = this ?: value
fun Double?.orDefault(value: Double) = this ?: value
// do the same for Float, Long, Char, Short and Byte 

Это приведет к желаемому поведению.

val default : Int = -1
val orDefault = b.orDefault(default.toDouble()) 

Примечание. Вам необходимо привести default к Double, поскольку получатель Double ожидает по умолчанию Double.

Выход:

-1.0
double

2-й способ

Если вы хотитепримите любой Number и верните его в тип получателя:

fun Int?.orDefault(value: Number) = this ?: value.toInt()
fun Double?.orDefault(value: Number) = this ?: value.toDouble()
// do the same for Float, Long, Char, Short and Byte 
0 голосов
/ 05 января 2019

Наконец, сделал что-то вроде этого:

fun <T : Number, J : Number> T?.orDefault(value: J): T = this ?: (value as T)

Это работает без переопределения всех типов чисел и возвращает правильный тип.

Единственное, что он может получить любое значение по умолчанию изТип номера.Как и для Int, он может принять двойное значение в качестве значения по умолчанию и вернуть его представление int.

0 голосов
/ 30 декабря 2018

В первом случае orDefault() ожидает один и тот же тип (T) как для приемника, так и для параметра.Поэтому, когда вы вызываете его с приемником Double и параметром Int, компилятор выводит свой ближайший общий суперкласс (Number) для параметра типа T.Затем он возвращает Int напрямую, как вы видите.

И хотя ваш второй случай выглядит больше как то, что вы хотите, я думаю, что он все еще выводит Number для T, так что приведение нене имеет никакого эффекта.

В конечном счете, я не думаю, что вы сможете делать то, что вы хотите, только с одной функцией расширения.Вы не можете разыграть Int до Double в Котлине (в отличие от Java);вам нужно вызвать его toDouble() метод.И вам нужно было бы кодировать это отдельно для каждого типа приемника.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...