स्केला में केवल एक फ़ील्ड में केस क्लास इंस्टेंस और क्लोन कैसे बदलें?


208

मान लीजिए कि मेरे पास एक केस क्लास है जो अलग-अलग सोशल नेटवर्क पर लोगों, लोगों का प्रतिनिधित्व करता है। उस वर्ग के उदाहरण पूरी तरह से अपरिवर्तनीय हैं, और अपरिवर्तनीय संग्रह में आयोजित किए जाते हैं, अंततः एक अक्का अभिनेता द्वारा संशोधित किया जाता है।

अब, मेरे पास कई क्षेत्रों के साथ एक केस क्लास है, और मुझे एक संदेश प्राप्त होता है, जिसमें कहा गया है कि मुझे किसी एक फ़ील्ड को अपडेट करना होगा, कुछ इस तरह से:

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)

ध्यान दें कि मुझे सभी क्षेत्रों को निर्दिष्ट करना है, भले ही केवल एक ही परिवर्तन हो। क्या मौजूदा फ़ील्ड को क्लोन करने और केवल एक फ़ील्ड को बदलने का एक तरीका है, जो सभी फ़ील्ड को निर्दिष्ट किए बिना, जो नहीं बदलता है? क्या मैं इसे एक लक्षण के रूप में लिख सकता हूं और इसे मेरे सभी केस वर्गों के लिए उपयोग कर सकता हूं?

यदि व्यक्ति मानचित्र जैसा उदाहरण होता, तो ऐसा करना आसान होता।

जवाबों:


324

case classएक copyविधि है जो इस उपयोग के लिए बिल्कुल समर्पित है:

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

5
वह दस्तावेज कहां है? मुझे उदाहरण के लिए "स्पष्ट" स्पॉट, scala-lang.org/api/current/index.html में कॉपी करने का संदर्भ नहीं मिल रहा है ।
फ्राँस्वा बेउसोलिल

6
यह भाषा की एक विशेषता है, आप इसे स्काला विनिर्देश में पा सकते हैं: scala-lang.org/docu/files/ScalaReference.pdf §5.3.2। यह एपीआई में नहीं है क्योंकि यह एपीआई का हिस्सा नहीं है;)
निकोलस

1
जब वे मौजूद होते हैं, तो मैं स्कैल्पडोक को कॉपी विधियों को दिखाने का इरादा रखता हूं, क्या यह नहीं है कि आप क्या चाहते हैं?
सामाजिक

4
यह अच्छा होगा। लेकिन यहाँ, फ्रांस्वा (अगर मैं सही हूं) की समस्या यह है कि वह नहीं जानता था कि copyअगर वह घोषणा करता है तो उसके पास एक तरीका होगा case class
निकोलस

2
@JonathanNeufeld आप उस भावना के साथ शुद्ध fp शिविर में कई मित्र बना लेंगे। मैं आप के साथ सहमत हूँ।
जवदाबा

46

2.8 के बाद से, स्काला केस क्लासेस में एक 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


0

पुस्तकालय 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तरीकों लिखें सुविधा पर थोड़ा कठिन हो सकता है। यह लेंस लाइब्रेरी का उपयोग करके सरल बनाने का एक अच्छा मौका होगा।

कृपया यह भी देखें:


0

मैं कॉम्प्लेक्स लेंस करने के लिए एक बड़ी लाइब्रेरी को शामिल नहीं करना चाहता था जो आपको नेस्टेड केस कक्षाओं में गहराई से मान सेट करने दें। यह पता चला है कि यह स्केलज़ लाइब्रेरी में कोड की कुछ पंक्तियाँ है :

  /** 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
  }

फिर आप लेंस बना सकते हैं जो बिल्ट इन कॉपी फीचर का उपयोग करने की तुलना में बहुत आसानी से नेस्टेड मान सेट करते हैं। यहाँ एक बड़े सेट का लिंक दिया गया है यदि जटिल लेंस जो कि मेरे पुस्तकालय में भारी नेस्टेड मान सेट करने के लिए उपयोग किया जाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.