写一个比 Java 更优雅的 Copyable 接口
Write a Copyable interface more elegant than in Java
我正在尝试编写一个 类 可以实现的接口,使它们 "copyable" 成为(类型)安全的可克隆对象。
在 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
}
}
显然这不是那么优雅,Copyable
和 Example
的 headers 看起来都过于复杂。在 Kotlin 中有没有更优雅的方法来实现这一点?
这是通过牺牲一些静态类型安全性来减少通用样板的尝试:
interface Copyable {
fun createCopy(): Copyable
}
inline fun <reified T : Copyable> T.copy(): T = createCopy() as T
我们可以利用扩展函数来获取接收器的泛型类型,而无需递归泛型。我们使扩展函数内联以具体化类型参数,以便检查转换并在实现 class 没有 return 相同类型的实例时抛出异常。
这是一个用法示例
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
方法是通用的,因为我们可以利用 covariance。像这样声明你的类型
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()
仍然可以编译。这是因为覆盖方法可以 return 比 super 方法更具体的类型,并且使用 Kotlin 的 single expression functions 我们想要的类型是自动推断的。
然而,如果您不直接使用特定类型,而是使用 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>
}
我正在尝试编写一个 类 可以实现的接口,使它们 "copyable" 成为(类型)安全的可克隆对象。
在 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
}
}
显然这不是那么优雅,Copyable
和 Example
的 headers 看起来都过于复杂。在 Kotlin 中有没有更优雅的方法来实现这一点?
这是通过牺牲一些静态类型安全性来减少通用样板的尝试:
interface Copyable {
fun createCopy(): Copyable
}
inline fun <reified T : Copyable> T.copy(): T = createCopy() as T
我们可以利用扩展函数来获取接收器的泛型类型,而无需递归泛型。我们使扩展函数内联以具体化类型参数,以便检查转换并在实现 class 没有 return 相同类型的实例时抛出异常。
这是一个用法示例
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
方法是通用的,因为我们可以利用 covariance。像这样声明你的类型
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()
仍然可以编译。这是因为覆盖方法可以 return 比 super 方法更具体的类型,并且使用 Kotlin 的 single expression functions 我们想要的类型是自动推断的。
然而,如果您不直接使用特定类型,而是使用 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>
}