2015-11-24 37 views
3

我需要修改案例類的多個字段,但不包含所有copy代碼。似乎沒有形狀是一個好方法。無形:使用記錄進行批量更新

example,我能以這種形式使用lens

lensA ~ lensB ~ lensC set(something)(valA, valB, valC)

這是很好的。但在我的情況下,嵌套字段並不是我最關心的問題(我確信它會: - <)。所以lens解決方案几乎是一樣的:

我想指出something.copy(a = valA, b = valB, c = valC)

的一件事是,不是所有的修改都必然發生的事情。在我的假情況下,我可能會根據上下文中的一些if/else來更新所有a,b,c或其中一些,或者其中一些,或者沒有。

因此,Record用這種用法是一個很值得我需要什麼:

someHList + ('a ->> valA) + ('b ->> valB) + ('c ->> valC)

即使最終:

Seq(
    'a ->> valA, 
    'b ->> valB, 
    'c ->> valC 
).fold(someHList)(_ + _) 

根據我的編譯器這是不可能的(收益率類型不匹配錯誤)。

我知道這個用法只存在於我的想象中,而不是文檔。不過,我真的很感謝使用Recordlens或任何解決我的問題的正確方法。任何其他優雅的方式也歡迎!

THX!

+0

你看過[點菜單類](https://github.com/milessabin/shapeless/blob/master/examples/src/main/scala/shapeless/examples/alacarte。scala)的例子? –

+0

@MilesSabin感謝您的快速回復!無形的岩石!然而我迷失在這裏。在點菜式的例子中,我只能得到一個非案例類模仿案例類。我應該怎麼做才能更新現有的案例類實例?我在這裏錯過了什麼嗎? – noru

回答

2

已經有update single field operation +通過Updater運行提供只有你需要的是通過some fold operation

運用它,就可以寫

import shapeless._ 
import shapeless.ops.hlist.LeftFolder 
import shapeless.ops.record.Updater 
import syntax.singleton._ 
import record._ 

object updateAll extends Poly2 { 
    implicit def updateOne[L <: HList, F](implicit update: Updater[L, F]) = at[L, F]((l, f) => update(l, f)) 
} 

implicit class UpdateAllOps[L <: HList](record: L) { 
    def ++>[U <: HList](updates: U)(implicit fl: LeftFolder[U, L, updateAll.type]): fl.Out = 
    fl(updates, record) 
} 

現在有

val rec = 'x ->> "Old" :: 'y ->> 1 :: HNil 
val upd = 'z ->> true :: 'x ->> "New" :: HNil 

你可以確認

reC++> upd 

是相同的是

'x ->> "New" :: 'y ->> 1 :: 'z ->> true :: HNil 

但重要的一點是

val str = "New".asInstanceOf[String with Serializable] 
reC++> ('x ->> str :: HNil) 

會導致類似

'x ->> "Old" :: y ->> 1 :: 'x -> "New" :: HNil 

所以你應該非常小心你的類型在這裏,除非你定義您自己的替代品Updater

+0

謝謝@Odomontois!它只是工作。我真的需要花一些時間採取無形101. – noru

+0

@noru如果只有這樣的東西(無形101)將存在... – Haspemulator