2016-11-29 64 views
0

我试图定义一个简单的CRUD系统使用的基本特征。但是,我需要基本特征来支持“copyWithId”def(因为Scala案例类的复制魔法不可用)。到目前为止,我已经找到了最好的办法是:定义一个scala特质def返回一个具体的子类型实例

trait Identifiable[ID, T] { 
    def id: Option[ID] 
    def copyWithId(id: Option[ID]): T 
} 

case class TestNamedIdentity(id: Option[Int], name: String) 
    extends Identifiable[Int, TestNamedIdentity] { 

    def copyWithId(id: Option[Int]): TestNamedIdentity = { 
    copy(id = id) 
    } 
} 

这工作,但因为它需要所有的具体实例与ID和自我扩展看起来有点笨重。我想写一些如下:

trait Identifiable[ID] { 
    this:X => 
    def copyWithId(id: Option[ID]): X 
    def id: Option[ID] 
} 

使用某种形式的自引用具体类。任何方式使这项工作?

更新:随着使用情况如下

的想法是使用它的代码就像

abstract class SomeClass[A <: IdentifiableEntity[ID], ID] { 
    def someFunc2: Option[ID] 
    def someFunc(item: A): A = { 
    item.copyWithId(someFunc2) 
    } 
} 

使用从@jwvh的解决方案需要调用后“asInstanceOf”铸造。哪些用于我的用例,但希望得到更优雅的解决方案。

item.copyWithId(someFunc2).asInstanceOf[A] 
+1

第一种形式是唯一一个我知道需要写一个涉及'Identifiable'也返回'T'参数化方法时很好地工作。重写复制方法看起来很笨重,但对于我认为更差的CRUD方法也是如此,所以我已经处理了它。除此之外,我能想到的最好的方法来保存一些样板文件将是一个宏,但它只会节省很多。以抽象的方式处理“copy”是非常棘手的。 –

+0

@MichaelZajac我担心宏将是唯一可行的解​​决方案,我不愿意为代码库添加这种级别的混淆。我认为jwvh的方法对于api消费者来说至少比我上面的第一种形式更清晰。 – rapidninja

回答

1

这似乎工作。

trait Identifiable[ID] { 
    def id: Option[ID] 
    def copyWithId(id: Option[ID]): Identifiable[ID] 
} 

然后案例类被简化。

case class TestNamedIdentity(id: Option[Int], name: String 
          ) extends Identifiable[Int] { 
    def copyWithId(id: Option[Int]): TestNamedIdentity = copy(id = id) 
} 
+0

然而,这样做还是有效的,然后它需要任何用法来回避。例如:'saved.copyWithId(id).asInstanceOf [A]'。所以基本上交易一个样板为另一个。对于具体的用例,我正在处理这些作品。谢谢 – rapidninja

+1

@rapidninja,我没有看到它。 copyWithId()的结果类型与case类中定义的一样。为什么需要铸造? 'saved.copyWithId()'应该与'saved'不同的类型吗? – jwvh

+0

我将示例添加到原始帖子中以解释用例以及为什么需要投射。 – rapidninja

相关问题