编写比Java更优雅的Copyable接口

托德·塞维尔

我正在尝试编写一个类可以实现的接口,以使它们“可复制”,(类型)安全的Clonable。

在Java中,我将使用递归泛型执行以下操作:

 public interface Copyable<C extends Copyable<C>> {
      C copy();
 }

 public class Example implements Copyable<Example> {
      ...

      @Override
      public Example copy()
      {
           return new Example(this); //invoke copy constructor
      }
 }

显然,这不是那么优雅,并且的标题CopyableExample看起来都过于复杂。在Kotlin中,有没有更优雅的方法来实现这一目标?

基里尔·拉赫曼(Kirill Rakhman)

这是通过牺牲一些静态类型安全性来减少通用样板的尝试:

interface Copyable {
    fun createCopy(): Copyable
}

inline fun <reified T : Copyable> T.copy(): T = createCopy() as T

我们可以利用扩展函数来获取接收器的泛型类型,而无需递归泛型。我们使扩展函数内联以验证类型参数,以便如果实现类未返回相同类型的实例,则将强制检查类型转换并引发异常。

这是一个示例用法

class Example(val a: String) : Copyable {
    constructor(e: Example) : this(e.a)

    override fun createCopy() = Example(this)
}


fun main(args: Array<String>) {
    val copiedExample: Example = Example("a").copy()
}

使用协方差的替代解决方案

根据您的用例,您甚至不需要copy通用方法,因为我们可以利用协方差这样声明您的类型

interface Copyable {
    fun copy(): Copyable
}

class Example(val a: String) : Copyable {
    constructor(f: Example) : this(f.a)

    override fun copy() = Example(this)
}

如您所见,代码val copiedExample: Example = Example("a").copy()仍然可以编译。这是因为重写的方法可以返回比super方法更具体的类型,并且使用Kotlin的单表达式函数可以自动推断出所需的类型。

但是,如果您不直接使用特定类型,而是说的子接口,则可能会导致问题Copyable以下代码无法编译:

interface CopyableIterable<T> : Iterable<T>, Copyable

class Example : CopyableIterable<String> {

    constructor(e: Example)

    override fun copy() = Example(this)
    override fun iterator() = TODO()
}

fun foo(ci: CopyableIterable<String>) {
    val copy: CopyableIterable<String> = ci.copy() // error: type mismatch
}

解决copy方法很简单,也可以覆盖子接口中方法:

interface CopyableIterable<T> : Iterable<T>, Copyable {
    override fun copy(): CopyableIterable<T>
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章