在 Kotlin 中使用数据 类 的特征?

Using traits with data classes in Kotlin?

我有两个定义为数据的模型对象/DTO classes

public data class ModelA(val limit: Int, val offset: Int, val someDataA: DataAlpha)
public data class ModelB(val limit: Int, val offset: Int, val someDataB: DataBeta)

我想根据 Paginable 特征来概括分页:

trait Paginable {
    var limit: Int
    var offset: Int
}

但是使 ModelA 实现可分页会导致错误:

错误:'offset' 隐藏超类型 'Paginable' 的成员并且需要 'override' 修饰符

添加覆盖

public data class ModelB(override val limit: Int, override val offset: Int, val someDataB: DataBeta) : Paginable

导致更有趣的错误,使编译器崩溃:

Error:java.lang.ClassCastException: org.jetbrains.kotlin.psi.JetParameter cannot be cast to org.jetbrains.kotlin.psi.JetProperty
    at org.jetbrains.kotlin.resolve.OverrideResolver.varOverriddenByVal(OverrideResolver.java:562)
    at org.jetbrains.kotlin.resolve.OverrideResolver.checkOverridesForMemberMarkedOverride(OverrideResolver.java:606)
    at org.jetbrains.kotlin.resolve.OverrideResolver.checkOverrideForMember(OverrideResolver.java:529)
    at org.jetbrains.kotlin.resolve.OverrideResolver.checkOverridesInAClass(OverrideResolver.java:269)
    at org.jetbrains.kotlin.resolve.OverrideResolver.checkOverrides(OverrideResolver.java:260)
    at org.jetbrains.kotlin.resolve.OverrideResolver.check(OverrideResolver.java:67)
    at org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer.analyzeDeclarations(LazyTopDownAnalyzer.java:299)
    at org.jetbrains.kotlin.resolve.LazyTopDownAnalyzerForTopLevel.analyzeDeclarations(LazyTopDownAnalyzerForTopLevel.java:77)
    at org.jetbrains.kotlin.resolve.LazyTopDownAnalyzerForTopLevel.analyzeFiles(LazyTopDownAnalyzerForTopLevel.java:69)
    at org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.java:147)
    at org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegrationWithCustomContext(TopDownAnalyzerFacadeForJVM.java:100)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.invoke(KotlinToJVMBytecodeCompiler.java:307)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.invoke(KotlinToJVMBytecodeCompiler.java:300)
    at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.java:232)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.java:299)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyzeAndGenerate(KotlinToJVMBytecodeCompiler.java:282)
    at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileBunchOfSources(KotlinToJVMBytecodeCompiler.java:208)
    at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.java:189)
    at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.java:49)
    at org.jetbrains.kotlin.cli.common.CLICompiler.exec(CLICompiler.java:148)
    at org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile.callCompiler(Tasks.kt:86)
    at org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile.compile(Tasks.kt:62)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:63)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.doExecute(AnnotationProcessingTaskFactory.java:218)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:211)
    at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:200)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:579)
    at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:562)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
    at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:64)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:42)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)

我知道可以在 class 主体内实现 "manually" 特征,但这会破坏数据 class 为 equalshashCodecopy 将忽略添加的属性。

您可以通过在两侧(traitdata class)使用相同的 属性 类型(val/var)来修复您的代码。

我正在寻找在 Kotlin 中实现多重继承的方法,遇到了 trait。但后来发现 traits 不存在了,一旦重命名为接口以匹配 Java 8 语义,它们的语义就发生了显着变化。

关键字 trait 是 Kotlin 中的关键字,但现在已删除。它在 Kotlin M12 版本中被弃用。

您可以找到更多 here