我有以下课程:
class C {
c1: Int,
c2: Int,
c3: String,
...
c40: Long
}
class A extends C {
a1: Int
}
class B extends C {
b1: Int,
b2: String
}
然后我需要在A的实例的基础上创建B的实例并复制从C继承的字段的所有值,如:
new B(50, "S", c1 = a.c1, c2 = a.c2, ..., c40 = a.c40)
但我想避免编写样板文件:c1 = a.c1, c2 = a.c2, ..., c40 = a.c40
如何以scala方式有效地完成此操作,但仍保持静态定义字段名称(不使用地图或其他无模式的方法)?
一种解决方案可能是使用组合:
class A {
a1: Int,
base: C
}
class B {
base: C,
b1: Int,
b2: String
}
然后写下:new B(50, "S", base = a.base)
但是在所有其他代码的情况下,如果我需要引用基础部分的值,我需要编写b.base.c1
而不是b.c1
- 我也想避免这种情况。
答案 0 :(得分:0)
您可以尝试使用一种使用案例类tupled
函数的hack。我可以想象你可以使用unapply
提取源类的字段,附加新参数并使用tupled
函数从扩展元组创建新类。
其中一个示例展示了如何使用无形shapeless tupples
很好地组合元组虽然听起来像是黑客。
答案 1 :(得分:0)
这可以通过稍微更改您的前置解决方案来完成。我将使用一个技巧,其中A
不是C
的子类,而是隐式子类型。
class C(val c1: Int, val c2: Int)
/*
* A does not extend C in this example.
* Using val to provide getters
*/
class A(val a1: Int, val base: C)
/*
* B does not extends C or A
*/
class B(val b1: Int, val base: C)
/*
* This is where the magic happens. This implicit will
* convert our A to a C and provide the values for C
*/
implicit def A2C(a: A): C = a.base
val myC = new C(1, 2)
// Wrap a C with our A
val myA = new A(3, myC)
// The implicit makes it seem that we are calling c1 from A
println(myA.c1)
// Now we can build a B from an A without any boilerplate
val myB = new B(4, myA)
// We need an implicit if we want to use a B as if it were a C
implicit def B2C(b: B): C = b.base
// And call C members without a messy b.base.c1 calls
println(myB.c1)
/*
* Now assume A extended C because you need it to be a sub-type. This is
* where a 'gotcha' raises its ugly head
*/
// A will be considered a C in this case
def useSomeC(value: C) {
println(value.c2)
}
// Use an A as if it were an actual sub-class of C
useSomeC(myA)
/*
* But Generics mixes everything up for us
*/
def useGeneric[Sub <: C](value: Sub) {
println(value.c2)
}
// Does not compile. A is not an actual sub-type of C
useGeneric(myA)
/*
* We can get around this a couple of ways. If we are using
* someone else's methods and they expect Sub <: C then we
* can force the implicit conversion before we make the call
*/
val convertedToC: C = myA
useGeneric(convertedToC)
// Which can be cleaned up a bit like this
useGeneric(myA: C)
/*
* But Scala does provide us with a tool to avoid this in our
* own methods.
* Note the <% instead of the <:
*/
def useSpecial[Sub <% C](value: Sub) {
println(value.c2)
}
// Compiles and works
useSpecial(myA)
我希望这个例子有所帮助。