Generics 在Kotlin中是否有一种方法要求泛型类型成为数据类?
以下内容不起作用,但希望能帮助您理解我的意思:Generics 在Kotlin中是否有一种方法要求泛型类型成为数据类?,generics,kotlin,data-class,Generics,Kotlin,Data Class,以下内容不起作用,但希望能帮助您理解我的意思: class Example<T : DataClass> 类示例 如果你想知道我正在努力完成什么,这是我所想的一个例子: class Repository<T> where T : Entity, // Entity defines mutable property 'id' T : DataClass { // assume there is a map her
class Example<T : DataClass>
类示例
如果你想知道我正在努力完成什么,这是我所想的一个例子:
class Repository<T> where T : Entity, // Entity defines mutable property 'id'
T : DataClass {
// assume there is a map here
fun add(obj: T) {
val copy = obj.copy(id = generateID())
map.put(copy.id, copy)
}
}
类存储库,其中T:Entity,//Entity定义可变属性“id”
T:数据类{
//假设这里有地图
趣味添加(obj:T){
val copy=obj.copy(id=generateID())
map.put(copy.id,copy)
}
}
或者有更好的方法来完成我想做的事情吗?没有,
数据
类在类型系统中没有任何特定的表示,无法与常规类区分()
但是,您可以要求具有一定数量组件的数据
类使用接口的方法(实际上它将是数据
类上的标记接口)
下面是包含两个组件的数据类的示例:
interface Data2<T1, T2> {
operator fun component1(): T1
operator fun component2(): T2
fun copy(t1: T1, t2: T2): Data2<T1, T2>
}
copy
函数不是完全类型安全的,因为Kotlin(并且没有办法要求接口实现是特定类型的子类型),但是如果您仅使用它标记数据
类,它应该可以工作(请参阅下面的另一个选项)
另一个缺点是您丢失了copy
方法的默认参数,并且必须使用指定的所有参数调用它:
val d = myD2.copy(newValue, myD2.component2())
另一种选择是将这些接口定义为Data2
,class Impl(…):Data2
,并使copy
返回Self
,但如果您将接口用作Data2
我感觉您真正想要的是它应该能够用一个新ID复制自己,并且有一个ID。不一定是一个数据类。所以你可以用一个接口来定义它
例如:
interface CopyableWithId<out T> where T: CopyableWithId<T> {
fun copy(newId: Long): T
val id: Long
}
data class BarBaz(override var id: Long, var name: String): CopyableWithId<BarBaz> {
override fun copy(newId: Long): BarBaz = copy(id = newId)
}
class Repository<T> where T : CopyableWithId<T>{
val map: MutableMap<Long, CopyableWithId<T>> = HashMap()
fun add(obj: T) {
val copy = obj.copy(generateID())
map.put(copy.id, copy)
}
private fun generateID(): Long {
return 1L
}
}
interface Copyable <T> {
fun copy(fields: T.() -> T): T
}
data class BarBaz(var id: Long, var name: String): Copyable<BarBaz> {
override fun copy(fields: BarBaz.() -> BarBaz): BarBaz {
val instance = fields(this)
return copy(id = instance.id, name = instance.name)
}
}
class Repository<T> where T : Copyable<T>{
val map: MutableMap<Long, Copyable<T>> = HashMap()
fun add(obj: T) {
val copy = obj.copy{id = generateID()}
map.put(copy.id, copy)
}
private fun generateID(): Long {
return 1L
}
}
接口CopyableWithId,其中T:CopyableWithId{
有趣的副本(newId:Long):T
valid:Long
}
数据类BarBaz(覆盖变量id:Long,变量名称:String):CopyableWithId{
覆盖有趣的复制(newId:Long):BarBaz=copy(id=newId)
}
类存储库,其中T:CopyableWithId{
val-map:MutableMap=HashMap()
趣味添加(obj:T){
val copy=obj.copy(generateID())
map.put(copy.id,copy)
}
private fun generateID():长{
返回1L
}
}
您还可以通过更通用的方式实现复制或组件1、组件2
例如:
interface CopyableWithId<out T> where T: CopyableWithId<T> {
fun copy(newId: Long): T
val id: Long
}
data class BarBaz(override var id: Long, var name: String): CopyableWithId<BarBaz> {
override fun copy(newId: Long): BarBaz = copy(id = newId)
}
class Repository<T> where T : CopyableWithId<T>{
val map: MutableMap<Long, CopyableWithId<T>> = HashMap()
fun add(obj: T) {
val copy = obj.copy(generateID())
map.put(copy.id, copy)
}
private fun generateID(): Long {
return 1L
}
}
interface Copyable <T> {
fun copy(fields: T.() -> T): T
}
data class BarBaz(var id: Long, var name: String): Copyable<BarBaz> {
override fun copy(fields: BarBaz.() -> BarBaz): BarBaz {
val instance = fields(this)
return copy(id = instance.id, name = instance.name)
}
}
class Repository<T> where T : Copyable<T>{
val map: MutableMap<Long, Copyable<T>> = HashMap()
fun add(obj: T) {
val copy = obj.copy{id = generateID()}
map.put(copy.id, copy)
}
private fun generateID(): Long {
return 1L
}
}
接口可复制{
有趣的副本(字段:T.()->T):T
}
数据类BarBaz(变量id:Long,变量名称:String):可复制{
覆盖有趣的复制(字段:BarBaz。->BarBaz):BarBaz{
val实例=字段(此)
返回副本(id=instance.id,name=instance.name)
}
}
类存储库,其中T:Copyable{
val-map:MutableMap=HashMap()
趣味添加(obj:T){
val copy=obj.copy{id=generateID()}
map.put(copy.id,copy)
}
private fun generateID():长{
返回1L
}
}
可能是不相关的,因为我有类似但略有不同的问题
我需要将共享逻辑移到一个超类,问题是我不能使用generict的copy方法。我发现了以下解决方法:
实体:
data class MyEntity(
val id: String,
val createdAt: Instant,
val updatedAt: Instant
)
摘要通用存储库:
abstract class GenericRepository<T> {
abstract val copyFn: KCallable<T>
fun add(obj: T) {
val instanceParameter = copyFn.instanceParameter!!
val idParameter = copyFn.findParameterByName("id")!!
val copy = copyFn.callBy(
mapOf(
instanceParameter to obj,
idParameter to "new id"
)
)
// Do whatever you want with the copy
}
}
abstract class BetterGenericRepository<T> {
abstract val copyFn: KCallable<T>
fun add(obj: T): T {
val instanceParameter = getInstanceParameter()
val idParameter = getParameterByName(instanceParameter, "id")
val updatedAtParameter = getParameterByName(instanceParameter, "updatedAt")
val copy = copyFn.callBy(
mapOf(
instanceParameter to obj,
idParameter to "new id",
updatedAtParameter to Instant.now()
)
)
// Do whatever you want with the copy
return copy
}
private fun getInstanceParameter() =
copyFn.instanceParameter
?: throw RuntimeException("${copyFn.returnType} must be Data Class or its method '${copyFn.name}' must have 'instanceParameter' as KParameter")
private fun getParameterByName(instanceParameter: KParameter, name: String) =
copyFn.findParameterByName(name)
?: throw RuntimeException("${instanceParameter.type} must have '$name' property")
}
结果
MyEntity(id=1, createdAt=1970-01-01T00:00:00Z, updatedAt=1970-01-01T00:00:00Z)
MyEntity(id=new id, createdAt=1970-01-01T00:00:00Z, updatedAt=2020-08-26T13:29:42.982Z)
是否担心这会导致无限循环?当我们不能真正调用super.copy时,它不会递归调用copy吗?我给我的copyID
命名只是为了确定。它正在工作。复制来自数据类。副本名称可以是克隆或其他名称。
MyEntity(id=1, createdAt=1970-01-01T00:00:00Z, updatedAt=1970-01-01T00:00:00Z)
MyEntity(id=new id, createdAt=1970-01-01T00:00:00Z, updatedAt=2020-08-26T13:29:42.982Z)