[scala] 사례 클래스 인스턴스를 복제하고 스칼라에서 하나의 필드 만 변경하는 방법은 무엇입니까?

다른 소셜 네트워크에있는 페르소나를 대표하는 사례 클래스가 있다고 가정 해 보겠습니다. 해당 클래스의 인스턴스는 완전히 불변이며 불변 컬렉션에 보관되어 결국 Akka 액터에 의해 수정됩니다.

이제 필드가 많은 케이스 클래스가 있으며 필드 중 하나를 업데이트해야한다는 메시지가 표시됩니다.

case class Persona(serviceName  : String,
                   serviceId    : String,
                   sentMessages : Set[String])

// Somewhere deep in an actor
val newPersona = Persona(existingPersona.serviceName,
                         existingPersona.serviceId,
                         existingPersona.sentMessages + newMessage)

하나만 변경하더라도 모든 필드를 지정해야합니다. 변경되지 않는 모든 필드를 지정하지 않고 기존 개인을 복제하고 하나의 필드 만 바꾸는 방법이 있습니까? 특성으로 작성하여 모든 사례 수업에 사용할 수 있습니까?

페르소나가 맵과 같은 인스턴스라면 쉽게 할 수 있습니다.



답변

case classcopy이 사용법에 정확히 맞는 방법이 제공됩니다.

val newPersona = existingPersona.copy(sentMessages =
                   existingPersona.sentMessages + newMessage)


답변

2.8부터 Scala 사례 클래스에는 copy명명 된 / 기본 매개 변수를 사용하여 마법을 사용 하는 메소드가 있습니다.

val newPersona =
  existingPersona.copy(sentMessages = existing.sentMessages + newMessage)

Persona사용법을 단순화 하는 방법을 만들 수도 있습니다 .

case class Persona(
  svcName  : String,
  svcId    : String,
  sentMsgs : Set[String]
) {
  def plusMsg(msg: String) = this.copy(sentMsgs = this.sentMsgs + msg)
}

그때

val newPersona = existingPersona plusMsg newMsg


답변

existingPersona.copy(sentMessages = existingPersona.sentMessages + newMessage)


답변

라이브러리 lens에서 사용 하는 것을 고려하십시오 Shapeless.

import shapeless.lens

case class Persona(serviceName  : String,
                   serviceId    : String,
                   sentMessages : Set[String])
// define the lens
val messageLens = lens[Persona] >> 'sentMessages

val existingPersona = Persona("store", "apple", Set("iPhone"))

// When you need the new copy, by setting the value,
val newPersona1 = messageLens.set(existingPersona)(Set.empty)
// or by other operation based on current value.
val newPersona2 = messageLens.modify(existingPersona)(_ + "iPad")

// Results:
// newPersona1: Persona(store,apple,Set())
// newPersona2: Persona(store,apple,Set(iPhone, iPad))

또한, 경우에 당신은 중첩 된 경우 클래스의 gettersetter 메소드는 작성하는 데 약간 지루할 수 있습니다. 렌즈 라이브러리를 사용하여 단순화 할 수있는 좋은 기회입니다.

다음도 참조하십시오 :


답변

중첩 된 케이스 클래스에서 값을 깊게 설정할 수있는 복잡한 렌즈를 만들기 위해 큰 라이브러리를 포함하고 싶지 않았습니다. scalaz 라이브러리 의 코드 는 몇 줄에 불과합니다 .

  /** http://stackoverflow.com/a/5597750/329496 */
  case class Lens[A, B](get: A => B, set: (A, B) => A) extends ((A) => B) with Immutable {
    def apply(whole: A): B = get(whole)

    def mod(a: A, f: B => B) = set(a, f(this (a)))

    def compose[C](that: Lens[C, A]) = Lens[C, B](
      c => this(that(c)),
      (c, b) => that.mod(c, set(_, b))
    )

    def andThen[C](that: Lens[B, C]) = that compose this
  }

그런 다음 내장 된 복사 기능을 사용하는 것보다 훨씬 중첩 된 값을 설정하는 렌즈를 만들 수 있습니다. 내 라이브러리가 복잡한 렌즈를 사용하여 중첩 된 값을 설정하는 경우 큰 세트에 대한 링크가 있습니다.


답변