Учитывая следующий код Котлина:
class Foo<T>(val t : T?)
fun <T : Any, R : Any> Foo<T?>.transform(transformer : (T) -> R) : Foo<R?> {
return when (t) {
null -> Foo(null)
else -> Foo(transformer(t))
}
}
fun main(args : Array<String>) {
val foo = Foo(args.firstOrNull())
val bar = foo.transform<String, Int> { t -> t.length }
val baz = bar.transform<Int, IntRange> { t -> t..(t + 1) }
}
Почему я получаю следующую ошибку: Type mismatch. Required: Foo<String?> Found: Foo<String>
Если я удаляю ?
из функции расширения, чтобы быть Foo<T>.transform
Вместо этого я получаю следующую ошибку: Type mismatch. Required: Foo<Int> Found: Foo<Int?>
Я могу понять вторую ошибку, потому что вы не можете присвоить Int?
Int
, но первая не имеет никакого смысла, так как вы можете назначитьString
до String?
РЕДАКТИРОВАТЬ:
Я изменил class Foo<T>
на class Foo<out T>
, и это работает для меня, так как значение t
будет прочитано только послепервоначальное назначение.С этой опцией мне не нужно определять параметры типа на сайте вызова transform
.
Другая найденная мною опция, которая мне кажется немного грязной (и я не уверен, почему это имеет значение)добавив параметр третьего типа в функцию расширения следующим образом:
fun <T : Any, U : T?, R : Any> Foo<U>.transform(transformer : (T) -> R) : Foo<R?>
С другой стороны, сайт вызова этого приложения я считаю немного странным.Глядя на приведенный выше код, вызов foo.transform
НЕ ДОЛЖЕН включать параметры типа, но вызов bar.transform<Int, Int?, IntRange>
MUST включает параметры типа для работы.
Этот параметр позволяет установить значение t
на более позднем этапе, если оно будет var
вместо val
.Но он также удаляет умное приведение к t
в функции transform
.Хотя это можно обойти с помощью !!
, если вас не волнуют условия гонки или (с некоторыми дополнительными усилиями) ?:
или ?.
, если вас беспокоит состояние гонки.