2015-01-02 4 views
5

में टाइप-सेफ़ जेनेरिक केस क्लास अपडेट्स मैं कुछ कोड लिखने का प्रयास कर रहा हूं जो रिकॉर्ड में बदलाव ट्रैक करता है और बाद में उन्हें लागू करता है। एक गतिशील भाषा में मैं सूची [(स्ट्रिंग, कोई भी)] जोड़े का लॉग रखकर ऐसा करूँगा, और फिर अंततः मूल रिकॉर्ड में अपडेट के रूप में इसे लागू करूँगा जब मैं अंततः परिवर्तन करने का निर्णय लेता हूं।स्कैला

मुझे अपडेट पर आत्मनिरीक्षण करने में सक्षम होना चाहिए, इसलिए अपडेट फ़ंक्शंस की एक सूची उचित नहीं है।

स्कैला में यह प्रतिबिंब का उपयोग करके काफी मामूली है, हालांकि मैं एक प्रकार-सुरक्षित संस्करण को कार्यान्वित करना चाहता हूं।

मेरा पहला प्रयास बेकार के साथ प्रयास करना था। यदि हम विशिष्ट प्रकार जानते हैं तो यह अच्छी तरह से काम करता है।

import shapeless._ 
import record._ 
import syntax.singleton._ 

case class Person(name:String, age:Int) 
val bob = Person("Bob", 31) 
val gen = LabelledGeneric[Person] 

val updated = gen.from(gen.to(bob) + ('age ->> 32)) 

// Result: Person("Bob", 32) 

हालांकि मैं यह काम नहीं कर सकता कि यह काम सामान्य रूप से कैसे किया जाए।

trait Record[T] 
    def update(???):T 
} 

आकारहीन तरीके से इसे संभालने के तरीके को देखते हुए, मुझे यकीन नहीं है कि यह भी संभव होगा?

यदि मैं बहुत सारे बॉयलरप्लेट को स्वीकार करता हूं, एक गरीब मनुष्य संस्करण के रूप में मैं निम्नलिखित के साथ कुछ कर सकता हूं।

object Contact { 
    sealed trait Field[T] 
    case object Name extends Field[String] 
    case object Age extends Field[Int] 
} 

// A typeclass would be cleaner, but too verbose for this simple example. 
case class Contact(...) extends Record[Contact, Contact.Field] { 
    def update[T](field:Contact.Field[T], value:T) = field match {   
     case Contact.Name => contact.copy(name = value) 
     case Contact.Age => contact.copy(age = value) 
    } 
} 

हालांकि यह विशेष रूप से सुरुचिपूर्ण नहीं है और इसमें बहुत सारे बॉयलरप्लेट की आवश्यकता है। मैं इसे संभालने के लिए शायद अपना खुद का मैक्रो लिख सकता हूं, हालांकि यह काफी आम बात की तरह लगता है - क्या यह पहले से ही बेकार या इसी तरह की मैक्रो लाइब्रेरी के साथ इसे संभालने का कोई तरीका है?

+0

क्या आपने ऑप्टिक्स (लेंस, प्रिज्म इत्यादि) पर एक नज़र डाली है? – rightfold

+0

यदि मैं लेंस को सही ढंग से समझता हूं, तो वे मुझे रिकॉर्ड को स्पष्ट रूप से अपडेट करने की अनुमति देते हैं, लेकिन उन बदलावों के बारे में मेटाडेटा लॉग नहीं करते जिन्हें मैं बाद में लागू करना चाहता हूं? –

+3

मुझे लगता है कि आकारहीन आपको आवश्यक भागों में से अधिकांश प्रदान करता है। आप नवीनतम आकारहीन 2.1.0 स्नैपशॉट में सुरक्षित डेल्टा और केस क्लास ला ला कार्टे उदाहरणों को देख सकते हैं। इसके अलावा आपका प्रश्न इतना सटीक नहीं है कि मैं आपके लिए पूरी चीज लिखने के बिना इसका उत्तर दे सकता हूं ;-) –

उत्तर

1

कक्षा के पूरे उदाहरण को अद्यतन के रूप में उपयोग करने के बारे में कैसे?

case class Contact(name: String, age: Int) 
case class ContactUpdate(name: Option[String] = None, age: Option[Int] = None) 

object Contact { 
    update(target: Contact, delta: ContactUpdate) = Contact(
     delta.name.getOrElse(target.name) 
     target.age.getOrElse(delta.age) 
    ) 
} 
// also, optionally this: 
object ContactUpdate { 
    apply(name: String) = ContactUpdate(name = Option(name)) 
    apply(age: Int) = ContactUpdate(age = Option(age)) 
} 

मुझे लगता है कि, अगर तुम सच में टाइप करें-सुरक्षित समाधान चाहते हैं, यह साफ और सबसे पठनीय, और यह भी, संभवतः कम से कम दर्द, को लागू करने के रूप में आप रिकॉर्ड्स से निपटने के लिए की जरूरत नहीं है, लेंस है और व्यक्तिगत क्षेत्र वर्णनकर्ता, बस ContactUpdate(name="foo") एक अद्यतन बनाता है, और updates.map(Contact.update(target, _)) अनुक्रम में सभी को लागू करता है।