在Kotlin中有应用于可序列化类型的接口吗?

ubof19bj  于 2022-12-23  发布在  Kotlin
关注(0)|答案(1)|浏览(152)

我想创建一个类,大致如下所示:

class MyWrapperClass<T: IsSerializable>(val someData: T) {
  fun stringifyMe(): String {
    return Json.encodeToString(someData)
  }
  

}

我的问题是关于IsSerializable类型的。我想只接受标记为@Serializable的类型,这样我就可以在它们上面调用Json.encodeToString()。这可能吗?
我尝试了上面提到的代码,但是我得到了错误“不能使用'T'作为物化类型参数。请使用类代替。"。

kknvjkwl

kknvjkwl1#

KotlinSerialisation的工作方式是,通过在编译时处理@Serializable注解,在类的 * 伴随对象 * 中生成每个可序列化事物的序列化代码。
比如说

@Serializable
class Foo(val name: String)

变成

@Serializable
class Foo(val name: String) {
    companion object {
        fun serializer(): KSerializer<Foo> {
            // implementation details...
            // returns a serializer for Foos in some way 
        }
    }
}

接口不能要求一个类型有一个伴随对象。毕竟,接口只能要求与类型的 * 示例 * 相关的东西。所以没有接口可以做到这一点。
正如this Kotlin forums comment中所述,保证序列化成功的一种方法是要求调用者传入生成的serializer()

class MyWrapperClass<T>(
    val someData: T, 
    val strategy: SerializationStrategy<T>
) {
    fun stringifyMe(): String {
        return Json.encodeToString(strategy, someData)
    }
}

如果调用方具有可序列化类型,则它们可以执行以下操作:

MyWrapperClass(someData, SomeSerializableType.serializer())

即使一个类型没有标记为@Serializable,但是调用者已经使用其他方法得到了一个SerializationStrategy,也可以序列化这个示例,根据定义,“可序列化”也是如此。
我不推荐这样做,但也可以声明这两个接口:

interface SerializationStrategyProvider<T> {
    fun serializer(): SerializationStrategy<T>
}

interface MySerializable<T: MySerializable<T>> {
    val serializationStrategyProvider: SerializationStrategyProvider<T>
}

那么你的 Package 类就只能有一个参数:

class MyWrapperClass<T: MySerializable>(val someData: T) {
    fun stringifyMe(): String {
        return Json.encodeToString(someData.serializationStrategyProvider.serializer(), someData)
    }
}

但是缺点当然是调用者在使用你的类之前需要实现这个接口,你不能强制他们实现这个接口的方式。

@Serializable
data class Foo(val bar: String): MySerializable<Foo> {
    companion object: SerializationStrategyProvider<Foo>
    override val serializationStrategyProvider
        get() = Foo
}

相关问题