2012-12-09 34 views
1

假设我有一个特点定义了一些抽象的价值领域:如何复制实例和覆盖值字段特质宣布

trait Base { 
    val toBeOverride: String 
} 

case class Impl(other:Int) extends Base { 
    override val toBeOverride = "some value" 
} 

我如何编写一个函数,我可以很容易地得到一个克隆的实例只重写toBeOverride的值如下:

// copy only available to case class instance 
// v does not have method 'copy' 
def overrideBaseValue[T <: Base](v: Base) = 
    v.copy(toBeOverride = "prefix" + v.toBeOverride) 

编辑

@ SOM-snytt,我不认为这是一个重复,就像一个Trait是不一样的一个Abstract Class。这个问题的答案不满足我,见下文。

@布莱索尔,是的,这是一个问题。对于每个子案例类的实例,toBeOverride字段是相同的,所以它不应出现在构造函数中。

现在所有的建议都是在每个(!)子例子类中定义一个自定义的copy方法,在我看来这是丑陋的,并且显示出语言的不可用性。

+1

你需要案例类吗?你可以使用toBeOverride方法重新创建一个基本特征的新实例吗?像这样:'def overrideBaseValue(v:Base)= new Base {def toBeOverride =“prefix”+ v.toBeOverride}' – rjsvaljean

+0

http://stackoverflow.com/questions/12370244/case-class-copy-method- with-superclass –

+0

@rjsvaljean,是的,当我说“复制”时,我想保留case类实例的所有其他字段,例如示例中的“other”。 – xiefei

回答

0

由于性状不会自动复制方法,您可以尝试使用Base情况下类,而不是:

case class Base(toBeOverride: String) 

    case class Impl(other: Int, someVal: String = "some value") extends Base(someVal) 

    def overrideBaseValue[T <: Base](v: Base) = 
     v.copy(toBeOverride = "prefix" + v.toBeOverride) 

,你要运行到,虽然这个问题,是copy返回的一个实例Base,我不认为你可以将它转换回原来的Impl类。举例来说,这不会编译:

def overrideBaseValue[T <: Base](v: T): T = 
     v.copy(toBeOverride = "prefix" + v.toBeOverride) 
+4

也不推荐使用案例类继承。 – drexin

1

最简单的解决方法就是添加你要基材的制备方法:

trait Base { 
    val toBeOverride: String 
    def copyBase(newToBeOverridden: String): Base 
} 

case class Impl(other:Int, override val toBeOverride: String = "some value") extends Base { 
    def copyBase(newToBeOverridden: String) = copy(toBeOverride = newToBeOverridden) 
} 

这也允许直接创建的Impl一个实例,同时指定值为toBeOverride(这是不可能的)。唯一的缺点是现在使用Impl的模式匹配必须更改语法 - 如果这是一个问题,请更新您的问题并添加注释。

顺便说一句,如果你只是想添加一个前缀(如你的例子),那也没问题:

case class Impl(other:Int, override val toBeOverride: String = "some value") extends Base { 
    def copyBase(newToBeOverridden: String) = copy(toBeOverride = toBeOverride + newToBeOverridden) 
} 
1

这里有两种机制。

显然,在不久的将来,你将能够编写一个可以发出匿名子类的宏,但在那之前,我认为这个类型类并不是很艰难。

只需在Dynamic上踢轮胎即可。

import scala.language.dynamics 
import scala.reflect._ 
import scala.reflect.runtime.{ currentMirror => cm } 
import scala.reflect.runtime.universe._ 

trait Base { 
    def m: String 
} 
case class Impl(p: Int) extends Base { 
    override val m = "some value" 
} 

trait Basic extends Dynamic { 
    protected def m: String 
    def selectDynamic(f: String): Any = 
    if ("m" == f) m else reflecting(this, f) 
    protected def reflecting(b: Basic, f: String) = { 
    val im = cm.reflect(b) 
    val member = im.symbol.typeSignature member newTermName(f) 
    require(member != NoSymbol, s"No such member $f") 
    (im reflectMethod member.asMethod)() 
    } 
} 
case class Implic(p: Int) extends Basic { 
    override protected val m = "some value" 
} 

object Test extends App { 

    implicit class Copy[A <: Base](val b: A) { 
    def overriding(overm: String): A = (b match { 
     case impl: Impl => new Impl(impl.p) { override val m = overm } 
     case b: Base => new Base { override val m = overm } 
    }).asInstanceOf[A] 
    } 
    implicit class Proxy[A <: Basic : ClassTag](val b: A) { 
    def proximately(overm: String): Basic = new Basic { 
     override val m = overm 
     override def selectDynamic(f: String): Any = 
     if ("m" == f) overm else reflecting(b, f) 
     override def toString = b.toString 
    } 
    } 

    // asked for this 
    //def overriding[T <: Base](v: Base) = v.copy(m = "prefix" + v.m) 

    /* want something like this 
    def overriding[T <: Base](v: Base) = new Impl(v.p) { 
    override val m = "some value" 
    } */ 

    val a = Impl(5) 
    val b = a overriding "bee good" 
    Console println s"$a with ${a.m} ~> $b with ${b.m}" 
    // or 
    val c = Implic(7) 
    val d = c proximately "dynomite" 
    Console println s"$c with ${c.m} ~> $d with ${d.m}" 
} 
+0

谢谢。我不会考虑'copy'版本。 'Dynamic' +'reflection'版本很好,但似乎除了d.m之外,对d的任何访问都将返回类型为'Any',这并不完美。 – xiefei