2014-04-21 18 views
7

के मामले वर्गों के बीच सुरक्षित रूप से कॉपी करने के खेतों आप यह मानते हुए निम्नलिखितविभिन्न प्रकार

case class Test1(a:String,b:Int,c:Char) 

case class Test2(a:String,b:Int) 

की तरह मामले श्रेणियां होती हैं और आप निम्न चर

val test1 = Test1("first",2,'3') 

val test2 = Test2("1st",20) 

साथ वर्गों का दृष्टांत वहाँ उपयोग करने के लिए एक रास्ता है .copy विधि (या अन्यथा), परीक्षण 1 में टेस्ट 2 के अंदर चर लागू करने के लिए,

val test3 = test1.copy(test2) //Note this isn't valid scala code 
// Result should be ("1st",20,'3') 

यदि शुद्ध स्केल में यह संभव नहीं है, तो यह बेकार 1/2 में कैसे किया जाएगा (वर्तमान कोड बेकार 1 में है, हालांकि हम समय पर किसी भी समय बेकार 2 में अपग्रेड करने की योजना बना रहे हैं)

+0

आप यह स्वचालित रूप से नाम पता लगाने करना चाहते हैं के साथ और उनसे मेल खाते हैं? – NightRa

+0

हां, इसलिए वे 'केस क्लास' क्यों हैं और 'tuples' – mdedetrich

उत्तर

13

इन निराकार 2.0.0 यह इतना तरह से किया जा सकता,

scala> import shapeless._ 
import shapeless._ 

scala> case class Test1(a: String, b: Int, c: Char) 
defined class Test1 

scala> case class Test2(a: String, b: Int) 
defined class Test2 

scala> val test1 = Test1("first", 2, '3') 
test1: Test1 = Test1(first,2,3) 

scala> val test2 = Test2("1st", 20) 
test2: Test2 = Test2(1st,20) 

scala> val test1Gen = Generic[Test1] 
test1Gen: ... = [email protected] 

scala> val test2Gen = Generic[Test2] 
test2Gen: ... = [email protected] 

scala> val test3 = test1Gen.from(test2Gen.to(test2) :+ test1.c) 
test3: Test1 = Test1(1st,20,3) 

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

हम इसे आकारहीन LabelledGeneric का उपयोग करके ठीक कर सकते हैं। LabelledGeneric मानचित्र केस क्लास मानों को बेकार एक्स्टेंसिबल रिकॉर्ड्स के साथ-साथ फ़ील्ड मानों के प्रकारों को कैप्चर करने के लिए, संबंधित स्कैला Symbol के सिंगलटन प्रकार के माध्यम से प्रकार के फ़ील्ड नामों को एन्कोड करता है। अतिरिक्त बुनियादी ढांचे का एक छोटा सा (जो मैं शीघ्र ही निराकार 2.1.0 को शामिल करेंगे) यह हमें कम से कम बॉयलरप्लेट साथ सुरक्षित रूप से मामला वर्गों के बीच मैप करने के लिए अनुमति देता है,

import shapeless._, record._, syntax.singleton._, ops.hlist.Remove 

/** 
* This will be in shapeless 2.1.0 ... 
* 
* Permute the elements of the supplied `HList` of type `L` into the same order 
* as the elements of the `HList` of type `M`. 
*/ 
trait Align[L <: HList, M <: HList] extends (L => M) { 
    def apply(l: L): M 
} 

object Align { 
    def apply[L <: HList, M <: HList] 
    (implicit alm: Align[L, M]): Align[L, M] = alm 

    implicit val hnilAlign: Align[HNil, HNil] = new Align[HNil, HNil] { 
    def apply(l: HNil): HNil = l 
    } 

    implicit def hlistAlign[L <: HList, MH, MT <: HList, R <: HList] 
    (implicit 
     select: Remove.Aux[L, MH, (MH, R)], 
     alignTail: Align[R, MT]): Align[L, MH :: MT] = new Align[L, MH :: MT] { 
    def apply(l: L): MH :: MT = { 
     val (h, t) = l.removeElem[MH] 
     h :: alignTail(t) 
    } 
    } 
} 

/** 
* This, or something like it, will be in shapeless 2.1.0 ... 
* 
* Utility trait intended for inferring a field type from a sample value and 
* unpacking it into its key and value types. 
*/ 
trait Field { 
    type K 
    type V 
    type F = FieldType[K, V] 
} 

object Field { 
    def apply[K0, V0](sample: FieldType[K0, V0]) = 
    new Field { type K = K0; type V = V0 } 
} 

object OldWineNewBottle { 
    case class From(s1: String, s2: String) 
    case class To(s2: String, i: Int, s1: String) 

    val from = From("foo", "bar") 

    val fromGen = LabelledGeneric[From] 
    val toGen = LabelledGeneric[To] 

    // Define the type of the i field by example 
    val iField = Field('i ->> 0) 

    val align = Align[iField.F :: fromGen.Repr, toGen.Repr] 

    // extend the fields of From with a field for 'i', permute into 
    // the correct order for To and create a new instance ... 
    val to = toGen.from(align('i ->> 23 :: fromGen.to(from))) 

    assert(to == To("bar", 23, "foo")) 
} 
+0

धन्यवाद, धन्यवाद, मुझे – mdedetrich

+0

हैलो की आवश्यकता है, क्या मध्य तत्व को हटाते समय टेस्ट 1 से टेस्ट 2 में रूपांतरण करने का कोई तरीका है? यानी: टेस्ट 1 ("पहला", 1, 3) टेस्ट 2 होना चाहिए ("पहला, 3) –

+0

धन्यवाद, अच्छा जवाब, 'फील्ड टाइप' क्या है? – Michaelzh

संबंधित मुद्दे