2015-03-24 17 views
20

Ben Safely copying fields between case classes of different types benzer bir şey yapmanın ancak yeniden sıralanmış alanları ile düşündüklerim alanlara sahip başka içineŞekilsiz - yani farklı sırayla

case class A(foo: Int, bar: Int) 
case class B(bar: Int, foo: Int) 

bir vaka sınıf açmak Ve ben bir dönüş için bir şey olsun isterim bir B(4, 3) içine A(3, 4) - LabelledGeneric şekilsiz

yılında ancak

LabelledGeneric[B].from(LabelledGeneric[A].to(A(12, 13))) 

sonuçlarına akla gelen

Kayıttaki (?) Alanları nasıl yeniden düzenlerim, böylece bu işlem en az boilerle çalışabilir mi?

+4

Bir makinede değilim Şu anda bir örnek oluşturabilirim, ancak kayıtlarda 'Hizala 'işlemine göz atmalısınız. –

cevap

29

Bunu Miles için bırakmalıyım ama mutlu bir saat olduğum yerden geliyorum ve dayanamıyorum. O, yukarıdaki bir yorumda işaret ettiği gibi, anahtar, kayıtlar için yalnızca iyi sonuç veren ops.hlist.Align'dur (her şeyden önce özel hlists).

Güzel bir sözdizimi isterseniz, tip parametre listesinin hedef parametresiyle (açıkça belirtmek istediğiniz) tip parametre listesinden diğer tüm öğelerle ayrılması için aşağıdaki gibi bir numara kullanmanız gerekir. sonra

case class A(foo: Int, bar: Int) 
case class B(bar: Int, foo: Int) 

Ve:

import shapeless._, ops.hlist.Align 

class SameFieldsConverter[T] { 
    def apply[S, SR <: HList, TR <: HList](s: S)(implicit 
    genS: LabelledGeneric.Aux[S, SR], 
    genT: LabelledGeneric.Aux[T, TR], 
    align: Align[SR, TR] 
) = genT.from(align(genS.to(s))) 
} 

def convertTo[T] = new SameFieldsConverter[T] 

Ve sonra: istiyorum) sonuç çıkarılmak

scala> convertTo[B](A(12, 13)) 
res0: B = B(13,12) 

Büyük harf sınıfları için hizalama örneklerinin bulunmasının derleme zamanında pahalılaşacağını unutmayın.

+3

Bu gülünç müthiş, teşekkürler Travis, Miles. – Utaal

+0

Harika, gerçekten :) – ahjohannessen

13

olarak @MilesSabin (tanrısal şekilsiz yaratıcısı), bir hizalama işlemi yoktur fark o gibi kullanılır:

import ops.hlist.Align 

val aGen = LabelledGeneric[A] 
val bGen = LabelledGeneric[B] 
val align = Align[aGen.Repr, bGen.Repr] 
bGen.from(align(aGen.to(A(12, 13)))) //> res0: B = B(13,12) 

P.S. Bir example on GitHub olduğunu farkettim.

+0

@TravisBrown Evet, sizinki daha güzel ve eksiksiz, genel cevaptır. – DaunnC

İlgili konular