Generics 如何在Kotlin中将vararg与不同的泛型一起使用?

Generics 如何在Kotlin中将vararg与不同的泛型一起使用?,generics,kotlin,Generics,Kotlin,我想将vararg与具有不同类型的每个参数的泛型一起使用 我已经尝试过的: class GeneralSpecification<T> { fun <P> ifNotNullCreateSpec(vararg propToCreateFun: Pair<P?, (P) -> Specification<T>>): List<Specification<T>> = propToCreateFun.

我想将vararg与具有不同类型的每个参数的泛型一起使用

我已经尝试过的:

class GeneralSpecification<T> {
    fun <P> ifNotNullCreateSpec(vararg propToCreateFun: Pair<P?, (P) -> Specification<T>>): List<Specification<T>> = 
       propToCreateFun.mapNotNull { (prop, funCreateSpec) ->
            prop?.let(funCreateSpec)
    }
...
}
(vararg对中的不同类型)


当我需要限制vararg中的类型时,如何将vararg与不同的泛型一起使用?(pair.first类型取决于pair.second类型)

如果要将不同的函数存储在一起,则需要将参数类型
T
out
变量一起处理。这意味着
T
仅用于类的输出。实际上,这意味着如果
派生的
扩展/实现了
基本的
,则允许
规范的转换

如果没有这样的约束,函数类型是不相关的,因此不能将它们存储在公共数组中(varargs只是数组参数的语法糖)

例如:

class Spec<out T>

fun createStringSpec() = Spec<String>()
fun createIntSpec() = Spec<Int>()

fun <T> ifNotNullCreateSpec(vararg pairs: Pair<T, () -> Spec<T>>) = Unit

fun main() {
    ifNotNullCreateSpec("asdf" to ::createStringSpec, 5 to ::createIntSpec)
}
类规范
fun createStringSpec()=Spec()
fun createIntSpec()=Spec()
有趣的ifNotNullCreateSpec(vararg对:对规范>)=单位
主要内容(){
ifNotNullCreateSpec(“asdf”到::createStringSpec,5到::createIntSpec)
}
使用参数
T
,如
(T)->Spec
,函数类型的输入中也会出现
T
类型。这意味着您不能再将函数类型存储在一起,因为它们采用不同类型的参数——您将使用哪种类型调用这样的函数

你需要做的是找到最常见的分母。一个示例是接受
任何
参数,并对实际类型执行运行时检查/分派


参见我最近的答案:

而不是使用<代码>配对>代码>,考虑定义自己的类型:

class WithSpec<P, T>(val prop: P?, val funCreateSpec: (P) -> Specification<T>) {
    fun spec() = prop?.let(funCreateSpec)
}
class-with-spec(val-prop:P?,val-funCreateSpec:(P)->规范){
fun spec()=prop?.let(funCreateSpec)
}
为什么??因为它允许你做

class GeneralSpecification<T> {
    fun ifNotNullCreateSpec(vararg propToCreateFun: WithSpec<*, T>): List<Specification<T>> = 
       propToCreateFun.mapNotNull { it.spec() }
    ...
}

ifNotNullCreateSpec(WithSpec("asdf", ::createStringSpec), WithSpec(5, ::createIntSpec))
类通用规范{
fun ifNotNullCreateSpec(vararg propToCreateFun:WithSpec):列表=
propToCreateFun.mapNotNull{it.spec()}
...
}
ifNotNullCreateSpec(带spec(“asdf”),带spec(5,::createIntSpec))
如果您想更接近原始代码,可以轻松地将
添加到使用spec返回
的类似于
的扩展函数中


看看你是否不知道
*
是什么意思。

很好的解决方案,谢谢!我必须更深入一点:使用这个
infix-fun

P?.ifNonNull(createSpecFun:(P)->规范)=这个?.let(createSpecFun)

我通过以下方式获得一个规范列表:
combinepc(specifications:list)
combinepc(listOf(“asdf”ifNonNull::createForName))
是的,这也是完全合理的。当然,您可以使用
vararg
来创建
combineSpec
class GeneralSpecification<T> {
    fun ifNotNullCreateSpec(vararg propToCreateFun: WithSpec<*, T>): List<Specification<T>> = 
       propToCreateFun.mapNotNull { it.spec() }
    ...
}

ifNotNullCreateSpec(WithSpec("asdf", ::createStringSpec), WithSpec(5, ::createIntSpec))