2015-11-24 3 views
3

У меня есть необходимость в изменении нескольких полей класса case без кода copy. Кажется бесформенным, это хороший способ пойти.Shapeless: пакетное обновление с использованием записи

Согласно example, я мог бы использовать lens в таком виде:

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

, который хорошо. Однако в моем случае вложенные поля не являются моей самой большой проблемой (я уверен, что это будет: - <). Таким образом, lens решение почти так же, как:

something.copy(a = valA, b = valB, c = valC)

Одна вещь, которую я хотел бы отметить, что не все модификации обязательно произошло. В моем псевдослучайном случае я могу обновить все a,b,c или некоторые из них, или ни одного, на основе некоторого if/else s в контексте.

Поэтому Record с этим видом использования является в значительной степени то, что мне нужно:

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

Даже в конечном счете:

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

что не возможно в соответствии с моим компилятором (выход типа рассогласование ошибка).

Я знаю, что это использование существует только в моем воображении, а не в документации. Однако я бы очень признателен за правильный способ использования Record или lens или что-то еще, чтобы решить мою проблему. Также приветствуется любой другой элегантный способ!

THX!

+0

Вы посмотрели [примеры занятий a la carte] (https://github.com/milessabin/shapeless/blob/master/examples/src/main/scala/shapeless/examples/alacarte.scala) пример? –

+0

@MilesSabin за ваш быстрый ответ! Бесплодные скалы! Однако я здесь потерялся. В примере a la carte я мог получить только класс случайных классов. Что мне следует сделать для обновления существующего экземпляра класса case? Я что-то упустил? – 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

Смежные вопросы