我该如何处理“不是被覆盖的子类型”错误

时间:2018-11-21 07:56:52

标签: generics kotlin generic-variance type-projection

我正在尝试在Kotlin中编写一些可验证的表单接口。在验证部分,我正在使用https://github.com/kamedon/Validation

这是我要运行的非常简单的代码;

import com.kamedon.validation.Validation


abstract class Validatable {
    abstract val validation: Validation<Any>

    fun validate() = validation.validate(this)
}

class LoginForm : Validatable() {
    val name: String = "Onur"
    val age: Int = 23

    override val validation = Validation<LoginForm> {
        "name" {
            be { name.length >= 5 } not "5 characters or more"
            be { name.length <= 10 } not "10 characters or less"
        }
        "age" {
            be { age >= 20 } not "Over 20 years old"
        }
    }
}


fun main(args: Array<String>) {
    val user = LoginForm()
    val result = user.validate()
    println(result)
}

这段代码给了我

Type of 'validation' is not a subtype of the overridden property 'public abstract val validation: Validation<Any> defined in Validatable'

如果我在Validatable中使用Validation<out Any>,它会说;

Kotlin: Out-projected type 'Validation<out Any>' prohibits the use of 'public final fun validate(value: T): Map<String, List<String>> defined in com.kamedon.validation.Validation'

如果我在Validatable中使用Validation<in Any>,它会说;

Kotlin: Type of 'validation' is not a subtype of the overridden property 'public abstract val validation: Validation<in Any> defined in Validatable'

如果我在LoginForm中使用Validation<Any>而不是Validation<LoginForm>,则代码将运行,但这次validation中的名称和年龄是从其内部的类使用的。我不想就图书馆的使用情况对此进行更改。

总有没有同时使用inout关键字,或者还有另一种方法可以实现我的目标。

1 个答案:

答案 0 :(得分:2)

您可以使抽象类Validatable成为通用类,并使子类提供一个对象,该对象同时公开Validation对象和本身作为target进行验证,例如

abstract class Validatable<T> {
    protected class ValidationInfo<T>(val target: T, val validation: Validation<T>)

    protected abstract val validationInfo: ValidationInfo<T>

    fun validate() = validationInfo.let { it.validation.validate(it.target) }
}

class LoginForm : Validatable<LoginForm>() {
    val name: String = "Onur"
    val age: Int = 23

    override val validationInfo = ValidationInfo(this, Validation {
        "name" {
            be { name.length >= 5 } not "5 characters or more"
            be { name.length <= 10 } not "10 characters or less"
        }
        "age" {
            be { age >= 20 } not "Over 20 years old"
        }
    })
}