Иногда я хочу иметь функцию расширения для универсального типа, чей параметр или возвращаемое значение является подтипом данного параметра типа, но без необходимости указывать этот фактический параметр типа. (может быть, если это не понятно, код прояснит это лучше?)
Используя подпись этот ответ :
inline fun <reified U : T, T> Iterable<T>.partitionByType(): Pair<List<U>, List<T>>
Это заставляет меня использовать его следующим образом:
val list : List<SomeType>
list.partitionByType<InterestedType, SomeType>()
Тем не менее, я хочу написать следующее:
list.partitionByType<InterestedType>()
Где InterestedType
является подтипом параметра типа списка, т.е. SomeType
. Оба решения выше должны затем дать мне Pair<List<InterestedType>, List<SomeType>>
в качестве возвращаемого значения.
Это, однако, на самом деле не возможно. Лучшее, что приходит мне в голову - это подпись, похожая на следующую:
inline fun <reified U : Any> Iterable<Any>.partitionByType(): Pair<List<U>, List<Any>>
Но тогда мы теряем фактический тип T
/ SomeType
, который был известен иначе. Непроверенный актерский состав все еще возможен на стороне вызывающей стороны, но это не то, что я хочу.
Так что мой вопрос: это как-то возможно? Имея что-то вроде U : T
, без указания T
? Или что-то запланировано в этом отношении (имеется в наличии KEEP или Kotlin)?
Для меня это звучит как разумная особенность, по крайней мере, до тех пор, пока она применяется только к функции расширения. Если это не так, то с какими проблемами я, вероятно, сейчас просто не обращаю внимания?
То, что я на самом деле не ищу, - это обходной путь (например, наличие промежуточного типа), но, возможно, оно того стоит, чтобы иметь его в качестве ответа.
Чем больше я об этом думаю. Разве не было бы правильнее, если бы функции расширения для универсальных типов были бы объявлены следующим образом?
fun SomeType<T>.extended()
вместо
fun <T> SomeType<T>.extended()
Потому что: если бы я контролировал SomeType<T>
и добавил бы эту функцию туда, мне не потребовалась бы какая-либо информация общего типа для ее объявления, например, тогда будет достаточно следующего:
fun extended()
То же самое в отношении функций с собственными родовыми типами, например ::1010 *
fun <U : T> extended2()
Добавление этого в качестве функции расширения теперь заставляет добавить T
-генерический тип, хотя тип, к которому мы хотели бы применить его, явно SomeType<T>
:
fun <T, U: T> SomeType<T>.extended2()