如何深度复制具有混杂特征的类 [英] How to deep copy classes with traits mixed in

查看:77
本文介绍了如何深度复制具有混杂特征的类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里有一些示例Scala代码。

Here's some sample scala code.

abstract class A(val x: Any) {  
    abstract def copy(): A  
}  

class b(i: Int) extends A(i) {  
    override def copy() = new B(x)  
}  

class C(s: String) extends A(s) {  
    override def copy() = new C(x)  
}  

//here's the tricky part  
Trait t1 extends A {  
    var printCount = 0  

    def print = {  
        printCount = printCount + 1  
        println(x)  
    }  

    override def copy = ???  
}  

Trait t2 extends A {  
    var doubleCount = 0  

    def doubleIt = {  
        doubleCount = doubleCount + 1  
        x = x+x  
    }  

    override def copy = ???  
}  

val q1 = new C with T1 with T2  
val q2 = new B with T2 with T1  

好的,正如您可能已经猜到的,这就是问题所在。
如何在T1和T2中实现复制方法,以便在它们与B,C或t2 / t1混合的情况下得到整个蜡球的副本?例如
,q2.copy应该返回T2为T1的新B,而q1.copy应该返回T1为T2的新C

OK, as you've likely guessed, here's the question. How can I implement copy methods in T1 and T2, such that weather they are mixed in with B, C, or t2/t1, I get a copy of the whole ball of wax? for example, q2.copy should return a new B with T2 with T1, and q1.copy should return a new C with T1 with T2

谢谢!

推荐答案

对象构造的组成



这里的基本问题是,在Scala以及我所知道的所有其他语言中,对象构造不是 compose 。考虑两个抽象操作 op 1 op 2 ,其中 op 1 使属性 p 1 为真,而 op 2 使属性 p 2 是。如果 op 1 ○op 2 <,这些操作相对于合成操作○ composable / em>将 p 1 p 2 都设为true。 (简单来说,属性还需要进行合成运算,例如之类的合取。)

Compositionality of object construction

The basic problem here is, that, in Scala as well as in all other languages I know, object construction doesn't compose. Consider two abstract operations op1 and op2, where op1 makes property p1 true and where op2 makes property p2 true. These operations are composable with respect to a composition operation ○, if op1 ○ op2 makes both p1 and p2 true. (Simplified, properties also need a composition operation, for example conjunction such as and.)

让我们考虑一下 new 操作和 new A():A 的属性,即通过调用 new A创建的对象的类型为 A new 操作缺少 compositionality ,因为其中没有操作/语句/功能 f 可让您编写新A 新B 的Scala,从而使 f(new A,新B):带有B 的A。 (简化,不要太想 A B 是否必须是类,特征或接口或其他东西)

Let's consider the new operation and the property that new A(): A, that is, an object created by calling new A is of type A. The new operation lacks compositionality, because there is no operation/statement/function f in Scala that allows you to compose new A and new B such that f(new A, new B): A with B. (Simplified, don't think too hard about whether A and B must be classes or traits or interfaces or whatever).

超级调用通常可以用来构成操作。请考虑以下示例:

Super-calls can often be used to compose operations. Consider the following example:

abstract class A { def op() {} }

class X extends A {
  var x: Int = 0
  override def op() { x += 1 }
}

trait T extends A {
  var y: String = "y"
  override def op() { super.op(); y += "y" }
}

val xt = new X with T
println(s"${xt.x}, ${xt.y}") // 0, y
xt.op()
println(s"${xt.x}, ${xt.y}") // 1, yy

X.op 的属性为 x 加1,然后将 T.op 的属性设置为 y s的长度增加一英寸。通过超级调用实现的构图兼具这两个特性。

Let X.op's property be "x is increased by one" and let T.op's property be "y's length is increased by one". The composition achieved with the super-call fulfils both properties. Hooooray!

让我们假设您正在使用 A类的字段为 x ,特征为 T1 的字段为 y 和另一个性状 T2 ,其字段为 z 。您想要的是以下内容:

Let's assume that you are working with a class A which has a field x, a trait T1 which has a field y and another trait T2 which has a field z. What you want is the following:

val obj: A with T1 with T2
// update obj's fields
val objC: A with T1 with T2 = obj.copy()
assert(obj.x == objC.x && obj.y == objC.y && obj.z == objC.z)

您的问题可以分为两个与构图相关的子问题:

Your problem can be divided into two compositionality-related sub-problems:


  1. 创建一个所需类型的新实例。这应该通过 construct 方法来实现。

  1. Create a new instance of the desired type. This should be achieved by a construct method.

Initialise 创建的对象,使其所有字段具有与源对象相同的值(为简便起见,我们将仅使用值类型的字段,而不使用引用类型的字段)。这应该通过初始化方法来实现。

Initialise the newly created object such that all its fields have the same values (for brevity, we'll only work with value-typed fields, not reference-typed ones) as the source object. This should be achieved by a initialise method.

第二个问题可以通过超级调用解决,第一个不能。

The second problem can be solved via super-calls, the first cannot. We'll consider the easier problem (the second) first.

让我们假设 construct 方法可根据需要工作,并产生正确类型的对象。类似于初始示例中的 op 方法的组成,我们可以实现 initialise ,这样每个类/特征 A T1 T2 实现初始化(objC),方法是将它知道的字段设置为 this 的相应值(单个效果),然后调用 super.initialise(objC)来构成这些单独的效果。

Let's assume that the construct method works as desired and yields an object of the right type. Analogous to the composition of the op method in the initial example we could implement initialise such that each class/trait A, T1 and T2 implements initialise(objC) by setting the fields it knows about to the corresponding values from this (individual effects), and by calling super.initialise(objC) in order to compose these individual effects.

据我所知,没有方法可以创建对象。如果要创建具有T1和T2的 A实例,则必须使用带有T1和T2的 new A 语句被处死如果超级呼叫可以在这里提供帮助,则类似

As far as I can see, there is no way to compose object creation. If an instance of A with T1 with T2 is to be created, then the statement new A with T1 with T2 must be executed somewhere. If super-calls could help here, then something like

val a: A = new A // corresponds to the "deepest" super-call
val at1: A with T1 = a with new T1

我实现了一个解决方案(参见要点)基于抽象类型成员和显式mixin类(类AWithT1WithT2将A扩展为T1和T2; val a = new AWithT1WithT2 而不是 val a = T1为T2的新A )。它可以工作,并且是类型安全的,但是既不是特别好也不简洁。显式的mixin类是必需的,因为 new A的 construct 方法必须将T1命名为T2

I implemented a solution (see this gist) based on abstract type members and explicit mixin classes (class AWithT1WithT2 extends A with T1 with T2; val a = new AWithT1WithT2 instead of val a = new A with T1 with T2). It works and it is type-safe, but it is neither particularly nice nor concise. The explicit mixin classes are necessary, because the construct method of new A with T1 with T2 must be able to name the type it creates.

其他类型安全性较低的解决方案也是可能的,例如,通过 asInstanceOf 或反射。

Other, less type-safe solutions are probably possible, for example, casting via asInstanceOf or reflection. I haven't tried something along those lines, though.

Scala宏也可能是一种选择,但是我还没有使用它们,因此对它的了解还不够。关于他们。编译器插件可能是另一个重量级的选择。

Scala macros might also be an option, but I haven't used them yet and thus don't know enough about them. A compiler plugin might be another heavy-weight option.

这篇关于如何深度复制具有混杂特征的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆