Rol*_*and 5 generics kotlin kotlin-extension
有时我想在泛型类型上有一个扩展函数,其参数或返回值是给定类型参数的子类型,但不必指定实际类型参数。(也许,如果不清楚,代码会更好地阐明它?)
使用此答案的签名:
inline fun <reified U : T, T> Iterable<T>.partitionByType(): Pair<List<U>, List<T>>
Run Code Online (Sandbox Code Playgroud)
它迫使我按如下方式使用它:
val list : List<SomeType>
list.partitionByType<InterestedType, SomeType>()
Run Code Online (Sandbox Code Playgroud)
但是,我更想写的是以下内容:
list.partitionByType<InterestedType>()
Run Code Online (Sandbox Code Playgroud)
其中InterestedType
是列表的类型参数的子类型,即SomeType
. 上面的两个解决方案都应该给我Pair<List<InterestedType>, List<SomeType>>
作为返回值。
然而,这实际上是不可能的。我想到的最好的是类似于以下的签名:
inline fun <reified U : Any> Iterable<Any>.partitionByType(): Pair<List<U>, List<Any>>
Run Code Online (Sandbox Code Playgroud)
但是随后我们丢失了其他已知的实际类型T
/ SomeType
。调用方仍然可以进行未经检查的强制转换,但这不是我所追求的。
所以我的问题是:这有可能吗?有类似的东西U : T
,没有指定T
?或者在这方面有什么计划(KEEP 或 Kotlin 问题可用)?
对我来说,这听起来像是一个合理的功能,至少只要它仅应用于扩展功能。如果不是,那么我目前可能只是忽略/忽略的问题是什么?我并不是真正要寻找的是一种解决方法(例如具有中间类型),但将其作为答案也可能是值得的。
我想得越多。如果泛型类型的扩展函数声明如下,不是更正确吗?
fun SomeType<T>.extended()
Run Code Online (Sandbox Code Playgroud)
代替
fun <T> SomeType<T>.extended()
Run Code Online (Sandbox Code Playgroud)
因为:如果我在控制之下SomeType<T>
并将在那里添加该函数,我将不需要任何泛型类型信息来声明它,例如以下内容就足够了:
fun extended()
Run Code Online (Sandbox Code Playgroud)
具有自己的泛型类型的函数也是如此,例如:
fun <U : T> extended2()
Run Code Online (Sandbox Code Playgroud)
现在将其添加为扩展函数会强制添加该T
-generic 类型,尽管我们希望应用它的类型显然是SomeType<T>
:
fun <T, U: T> SomeType<T>.extended2()
Run Code Online (Sandbox Code Playgroud)
注意:这只是针对“中级类型”解决方案部分的自我回答。我仍在寻找答案,是否可以在没有这种解决方法的情况下解决该问题,或者是否有计划支持它。
解决该问题的中间类型示例如下:
class PartitionType<T>
inline fun <reified T> type() = PartitionType<T>()
inline fun <reified U : T, T> Iterable<T>.partitionBy(type: PartitionType<U> = type()): Pair<List<U>, List<T>> {
val first = ArrayList<U>()
val second = ArrayList<T>()
for (element in this) {
if (element is U) first.add(element)
else second.add(element)
}
return Pair(first, second)
}
Run Code Online (Sandbox Code Playgroud)
这样就可以写:
list.partitionBy(type<InterestedType>())
Run Code Online (Sandbox Code Playgroud)
这将导致Pair<List<InterestedType>, List<SomeType>>
-return 值,但需要添加无论如何都不会使用的类型(间接使用除外; aninline class
在这里可能有意义,但是......那么参数应该是什么?)。
这里的关键是仅传递感兴趣的类型作为参数,而不是将其指定为请求的泛型类型(partitionBy<InterestedType, SomeType>()
仍然有效(或更正确地说:仍然需要))。
也许我用错了词,这就是为什么我还找不到合适的东西。或者也许这只是我想要拥有的东西而不是其他人?至少对我来说,听起来好像它可以/应该起作用。
另一种变体是在已知的类型上显式指定所有扩展函数,但是我们需要注意平台冲突,例如:
@JvmName("partitionSomeTypeByType") // only needed if we require more partitionByType-functions with differing generic type parameters
inline fun <reified U : SomeType> Iterable<SomeType>.partitionByType() = partitionBy<U, SomeType>()
Run Code Online (Sandbox Code Playgroud)
但这又只是一个解决方法。