2017-03-25 14 views
1

나는이 같은 trait 있습니다. 예를 들어 :스칼라 패턴 매칭의 조합 유형은

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-superclass-for-any-case-class –

답변

2

기본적으로 여기서하고 싶은 것은 실제 유형에 대한 추상입니다. 문제는 copy은 사례 클래스 측면에서만 OOTB로 구현되며, Identifiable은 특성이므로 copy 메서드가 컴파일 타임에 사용 가능할 수도 있고 그렇지 않을 수도 있습니다. 따라서 컴파일러가 왜 당신에게 고함을 지르고 있습니까?

가 심하게 this answer에서 영감을, 나는 볼품없는 렌즈를 사용하여 제공된 예 수정 :

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) 

수익률 :

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을 수정할 수 있습니다 :

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 스칼라는이 두 유형을 함께 유지하는 상위 유형을 찾으려고 시도합니다. 이 경우에는 식별 가능하며 copy 메소드가 없으므로 컴파일러가이를 확인할 수 없습니다.

다음 :

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

당신이 EntityA이 EntityB 당신이 "x는 같은 시간에 EntityA 및 EntityB 둘 다 유형입니다"라고한다고 가정

. 그러한 유형은 존재하지 않으며 확실히 복사 방법이있는 유형이 아닙니다.

일반 스칼라에서 수행하려는 방식대로 복사 방법을 일반적으로 추상화 할 수 있다고 생각하지 않습니다.

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) 
} 

이 당신의 작업 패턴 매칭으로 더 많은 이하 : 나는 당신의 가장 좋은 건 불행하게도 일부 상용구를 의미하므로처럼 하위 클래스의 각 방법을 사용자의 특성에 복사 방법을 추가하고 구현하는 것입니다 생각 단, 복제 호출을 엔티티 자체로 이동하는 경우는 예외입니다.

이제 일반 스칼라에만 적용됩니다. 이를 위해 Shapeless 나 Monocle과 같은 고급 라이브러리를 사용할 수 있습니다.

Case to case inheritence in Scala