다른 소셜 네트워크에있는 페르소나를 대표하는 사례 클래스가 있다고 가정 해 보겠습니다. 해당 클래스의 인스턴스는 완전히 불변이며 불변 컬렉션에 보관되어 결국 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 class
copy
이 사용법에 정확히 맞는 방법이 제공됩니다.
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))
또한, 경우에 당신은 중첩 된 경우 클래스의 getter
및setter
메소드는 작성하는 데 약간 지루할 수 있습니다. 렌즈 라이브러리를 사용하여 단순화 할 수있는 좋은 기회입니다.
다음도 참조하십시오 :
답변
중첩 된 케이스 클래스에서 값을 깊게 설정할 수있는 복잡한 렌즈를 만들기 위해 큰 라이브러리를 포함하고 싶지 않았습니다. 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
}
그런 다음 내장 된 복사 기능을 사용하는 것보다 훨씬 중첩 된 값을 설정하는 렌즈를 만들 수 있습니다. 내 라이브러리가 복잡한 렌즈를 사용하여 중첩 된 값을 설정하는 경우 큰 세트에 대한 링크가 있습니다.