gpt4 book ai didi

generics - Kotlin泛型Out-projected类型禁止使用

转载 作者:行者123 更新时间:2023-12-04 16:20:17 26 4
gpt4 key购买 nike

我正在使用一种来自后端的动态表单系统。为了能够映射我的表单,我有一个带有泛型的访问者模式,我让它在 Java 中工作,但我不能让它在 Kotlin 中工作。

我有这个界面:

internal interface FormFieldAccessor<T> {

fun getFormField(formFieldDefinition: FormFieldDefinition): FormField<T>

fun setValueToBuilder(builder: Builder, value: T)

fun accept(visitor: FormFieldVisitor)

fun getValue(personalInfo: PersonalInfo): T
}

然后我有这样的访问器列表:

val accessors = mutableMapOf<String, FormFieldAccessor<*>>()
accessors[FIRST_NAME] = object : FormFieldAccessor<String> {
override fun getValue(personalInfo: PersonalInfo): String {
return personalInfo.surname
}

override fun accept(visitor: FormFieldVisitor) {
visitor.visitString(this)
}

override fun getFormField(formFieldDefinition: FormFieldDefinition): FormField<String> {
//not relevant
}

override fun setValueToBuilder(builder: Builder, value: String) {
builder.withSurname(value)
}
}
//more other accessors with different type like Int or Boolean

并且想像这样使用它:

accessors[FIRST_NAME]!!.setValueToBuilder(builder, field.value )

但这不起作用并给我:

Out-projected type 'FormFieldAccessor<*>' prohibits the use of 'public abstract fun setValueToBuilder(builder: Builder, value: T): Unit defined in FormFieldAccessor'

如果你知道我做错了什么会很酷 :)

编辑:这是我拥有的结构的一个小要点 https://gist.github.com/jaumard/1fd1ccc9db0374cb5d08f047414a6bc8

我不想通过使用 Any 来放松类型,与 Java 相比感到沮丧,因为它真的很容易实现。我现在明白了星投影的问题,但是除了这个之外还有什么可以实现与 java 中相同的效果吗?

最佳答案

使用 star-projection表示您对实际类型一无所知,如文档所述:

Sometimes you want to say that you know nothing about the type argument, but still want to use it in a safe way. The safe way here is to define such a projection of the generic type, that every concrete instantiation of that generic type would be a subtype of that projection.

[...]

For Foo<out T : TUpper>, where T is a covariant type parameter with the upper bound TUpper, Foo<*> is equivalent to Foo<out TUpper>. It means that when the T is unknown you can safely read values of TUpper from Foo<*>.

您可以做的是转换为适当的类型:

(accessors[FIRST_NAME] as FormFieldAccessor<String>).setValueToBuilder(builder, field.value)

然而,这些类型的转换容易出错,更安全的方法如下;

object FormFieldProvider {
private val accessors = mutableMapOf<String, FormFieldAccessor<*>>()
fun <T : Any> addAccessor(key: String, fieldValidator: FormFieldAccessor<T>) {
accessors[key] = fieldValidator
}

@Suppress("UNCHECKED_CAST")
operator fun <T : Any> get(key: String): FormFieldAccessor<T> =
accessors[key] as? FormFieldAccessor<T>
?: throw IllegalArgumentException(
"No accessor found for $key")
}

对星空投影 map 的访问被包装在一个对象中,并且使用此解决方案访问值是安全的。

你可以这样使用它:

FormFieldProvider.addAccessor(FIRST_NAME, object : FormFieldAccessor<String> {
//...
})

FormFieldProvider.get<String>(FIRST_NAME).setValueToBuilder(...)

关于generics - Kotlin泛型Out-projected类型禁止使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49914841/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com