2017-03-25 8 views
1

私はこのようなtraitを持っています。例えば :Scalaのパターンマッチングで労働組合の種類は

case class EntityA(id: Option[Long], name: String, created: Date) extends Identifiable 

case class EntityB(id: Option[Long], price: Long, count: Int) extends Identifiable 

は、私がSeq[Identifiable]を持っていることを前提としていて、私はそれぞれに新しいidを割り当てます。

val xs: Seq[Identifiable] = ... 
xs.map { 
    case x: EntityA => x.copy(id = Some(nextId)) 
    case x: EntityB => x.copy(id = Some(nextId)) 
} 

良い:

最も簡単な方法は、のようです!しかし問題があります。 より多くのサブクラスを書くほど、より多くの(重複した)コードが作成されます。

私は連合タイプから助けを得ることを試みた:

xs.map { 
    case x: EntityA with EntityB => x.copy(id = Some(nextId)) 
} 

または

xs.map { 
    case x @ (_: EntityA | _: EntityB) => x.copy(id = Some(nextId)) 
} 

が、私は言うエラーました:Cannot resolve symbol copy

を任意の助けをいただければ幸いですが。おかげさまで

+0

:http://stackoverflow.com/questions/40995639/scala-how-to-define-an-abstractあなたが何をしようとしてにかなり似ているこの答えを参照してください。 -copyable-super-for-any-case-class –

答えて

2

基本的に、ここでやりたいことは、実際のタイプに対して抽象的です。その問題はcopyがケースクラスの点でOOTBにのみ実装されており、Identifiableは特性であるため、コンパイル時にcopyメソッドが利用可能かどうかはわかりません。なぜコンパイラがあなたに叫んでいるのですか?

this answerに触発され、私は型崩れのレンズを使用して提供される例変更:

import shapeless._ 

abstract class Identifiable[T](implicit l: MkFieldLens.Aux[T, Witness.`'id`.T, Option[Long]]){ 
    self: T => 
    final private val idLens = lens[T] >> 'id 

    def id: Option[Long] 
    def modifyId(): T = idLens.modify(self)(_ => Some(Random.nextLong())) 
} 

case class EntityA(id: Option[Long], name: String, create: Date) extends Identifiable[EntityA] 
case class EntityB(id: Option[Long], price: Long, count: Int) extends Identifiable[EntityB] 

をそして今、我々は自由のためIdentifable[T]を拡張する任意のタイプにそれぞれidを変更することができます。

val xs: Seq[Identifiable[_]] = Seq(EntityA(Some(1), "", new Date(2017, 1, 1)), EntityB(Some(2L), 100L, 1)) 
val res = xs.map(_.modifyId()) 
res.foreach(println) 

利回りを:

EntityA(Some(-2485820339267038236),,Thu Feb 01 00:00:00 IST 3917) 
EntityB(Some(2288888070116166731),100,1) 

この答えを@Kolmarが提供する上記のリンクに組み立てる個々のパーツについては素晴らしい説明があります。まず、他の答え(どのように非常に似ているか)についてのレンズ作用の仕組みを読んでから、これは、最小限の作業例を参照するためのものです。

さらに、@ Jasper-M answer hereを参照してください。

1

ユニオンタイプは正しいパスではありません。検討してください:

xs.map { 
    case x @ (_: EntityA | _: EntityB) => x.copy(id = Some(nextId)) 
} 

あなたはEntityA | EntityB Scalaは、これらの2つの型を一緒に保持するスーパータイプを見つけようとします。この場合は、識別可能です。これはコピーメソッドを持たないため、コンパイラはそれを解決できません。

次へ:あなたはEntityBでエンティティAを言うとき

xs.map { 
    case x: EntityA with EntityB => x.copy(id = Some(nextId)) 
} 

あなたは「xは同時にエンティティAとEntityB両方あるタイプである」言っています。そのようなタイプは存在しませんし、確かにその上にコピー方法を持っているものはありません。

残念ながら、私はあなたが一般的なScalaでやろうとしている方法でコピーメソッドを抽象化することはできないと思います。私はあなたの最善の策は、残念ながらいくつかの決まり文句を意味し、あなたの形質にコピー方法を追加し、そのようなあなたのサブクラスのそれぞれのメソッドを実装することだと思う:

trait Identifiable { 
    def id: Option[Long] 
    def copyWithNewId(newId: Option[Long]): Identifiable 
} 

case class EntityA(id: Option[Long], name: String) extends Identifiable { 
    override def copyWithNewId(newId: Option[Long]) = this.copy(id = newId) 
} 

case class EntityB(id: Option[Long], count: Int) extends Identifiable { 
    override def copyWithNewId(newId: Option[Long]) = this.copy(id = newId) 
} 

これは、多かれ少なかれ、作業パターンマッチングでありますただし、コピーコールをエンティティ自体に移動することは除きます。

これはプレーンなScalaにのみ適用されます。これを行うには、ShapelessやMonocleなどのより高度なライブラリを使用することができます。また、関連

Case to case inheritence in Scala

関連する問題