Kotlin 中是否有适用于可序列化类型的接口?

zv7*_*mnw 4 kotlin kotlinx.serialization

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

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

}
Run Code Online (Sandbox Code Playgroud)

我的问题是关于那种IsSerializable类型的。我只想接受已标记为 的类型@Serializable,以便我可以调用Json.encodeToString()它们。这可能吗?

我尝试了如上所述的代码,但收到错误“无法使用 'T' 作为具体化类型参数。请改用类。”。

Swe*_*per 5

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

所以像

@Serializable
class Foo(val name: String)
Run Code Online (Sandbox Code Playgroud)

变成

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

接口不能要求类型具有伴生对象。毕竟,接口只能需要与类型实例相关的东西。所以没有这个接口。

正如Kotlin 论坛评论中所述,保证成功序列化的一种方法是要求调用者传入生成的serializer()

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

如果调用者具有可序列化类型,那么他们可以执行以下操作:

MyWrapperClass(someData, SomeSerializableType.serializer())
Run Code Online (Sandbox Code Playgroud)

即使类型没有标记为@Serializable,但调用者已SerializationStrategy使用其他方式获得了 ,也可以序列化实例,因此根据定义,“可序列化”。


我不建议这样做,但也可以声明这两个接口:

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

interface MySerializable<T: MySerializable<T>> {
    val serializationStrategyProvider: SerializationStrategyProvider<T>
}
Run Code Online (Sandbox Code Playgroud)

那么你的包装类就可以只有一个参数:

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

但缺点当然是调用者需要实现这个接口才能使用你的类,并且你不能强制他们如何实现这个接口。预期的方式是:

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