2017-04-12 68 views
0

我想定義一個無形的LabelledGeneric,它在轉換爲HList時忽略一個(或多個)字段;當再次轉換HList時,它應該替換用戶定義的值。目標是能夠寫這樣的東西:Shapeless LabelledGeneric,但忽略一些字段

case class Foo(i: Int, s: String) 
val foo = Foo(123, "Hello") 

val gen = LabelledGeneric[Foo].ignoring('i)(defaultValue = -1) 
val hlist = gen.to(foo) 
// "Hello" :: HNil 

val foo2 = gen.from(hlist) 
assert(foo2 == Foo(-1, "Hello")) 

這是我到目前爲止。它編譯,但我不能讓種正常排隊隱式解析,當我嘗試使用它:

implicit class IgnoringOps[T](orig: LabelledGeneric[T]) { 
    def ignoring[Orig <: HList, V, Ign <: HList](k: Witness)(defaultValue: V)(implicit 
    gen: LabelledGeneric.Aux[T, Orig], 
    rem: Remover.Aux[Orig, FieldType[k.T, V], Ign], 
    upd: Updater.Aux[Ign, FieldType[k.T, V], Orig]): LabelledGeneric[T] = { 
    new LabelledGeneric[T] { 
     override type Repr = Ign 
     override def to(t: T): Ign = rem(gen.to(t)) 
     override def from(r: Ign): T = gen.from(upd(r, field[k.T](defaultValue))) 
    } 
    } 
} 

任何人都可以擺脫對我做錯了任何光線?

回答

0

這應該按預期(根據你的例子)工作:

implicit class IgnoringOps[T, L <: HList](gen: LabelledGeneric.Aux[T, L]) { 
    def ignoring[V, I <: HList, H <: HList](k: Witness)(v: V)(implicit 
     rem: Remover.Aux[L, k.T, (V, I)], 
     upd: Updater.Aux[I, FieldType[k.T, V], H], 
     ali: Align[H, L] 
    ): LabelledGeneric[T] = new LabelledGeneric[T] { 
     override type Repr = I 

     //`rem` is implicitly used there 
     override def to(t: T): I = gen.to(t) - k 

     //`upd` and `ali` are implicitly used there 
     override def from(r: I): T = gen.from(r + field[k.T](v)) 
    } 
    } 

注:

  • 刪除的隱含參數gen: LabelledGeneric.Aux[T, L]ignoring,您可以利用隱含類參數orig;
  • 使用-+方法從RecordOps而不是明確地使用remupd;
  • 更新remimplicit parameterRemover.Aux[L, FieldType[k.T, V], I],Remover.Aux[L, k.T, (V, I)];
  • 增加了中間幫手H <: HList;
  • 更新upd隱式參數,使用前面提到的中間助手,從Updater.Aux[I, FieldType[k.T, V], L]Updater.Aux[I, FieldType[k.T, V], H];
  • 新增ali隱含要求的HL對齊:ali: Align[H, L]
+0

啊哈!我錯過了隱藏的'Align',這是我忘記的(我傾向於將'record'視爲無序的Maps,當然,當重構case class實例時,排序很重要)。謝謝 :) –