Pytanie nie wspominając modyfikując danych, ale kiedy trzeba zrobić to szybko odkrywasz, że biblioteka Scala nie ma narzędzi, które ułatwiają to zadanie (gdy dane są niezmienne). Jeśli jeszcze tego nie doświadczyłeś, spróbuj wpisać funkcję, która zastąpi lub zmodyfikuje value
z posiadaną przez Person
, używając typów zdefiniowanych w pytaniu.
Jak opisano w Tony Morris 'Asymmetric Lenses in Scala, soczewki są odpowiednie rozwiązanie tego problemu.
Oto przykład, w jaki sposób możemy uzyskać dostęp i zaktualizować value
osoby za Cash
przy użyciu obiektywu (częściowe) implementacjach Lens
i PLens
od scalaz-seven gałęzi Scalaz.
Po pierwsze, niektóre dane podstawowe: zdefiniuj instancję Lens dla każdego pola klas case. A @[email protected] B
oznacza to samo co Lens[A, B]
.
val pants: Person @[email protected] Option[Pants] =
lensG(_.pants, p => ps => p.copy(pants = ps))
val pocket: Pants @[email protected] Option[Pocket] =
lensG(_.pocket, ps => p => ps.copy(pocket = p))
val cash: Pocket @[email protected] Option[Cash] =
lensG(_.cash, p => c => p.copy(cash = c))
val value: Cash @[email protected] String =
lensG(_.value, c => v => c.copy(value = v))
Nie możemy komponować wszystkich tych soczewek, jednak, ponieważ większość z tych dziedzin są owinięte w Option
typów.
częściowe Soczewki na ratunek: te pozwalają na dostęp i części Aktualizacja struktury, która może nie istnieć, takich jak wartość Some
wystąpienia Option
, albo head
z List
.
Możemy użyć funkcji somePLens
z Scalaz 7, aby utworzyć częściowy obiektyw oglądający każde opcjonalne pole.Jednakże, aby skomponować soczewkę częściową z jedną z naszych zwykłych soczewek, musimy uzyskać dostęp do równoważnej instancji soczewki częściowej dla zwykłego obiektywu, przy użyciu metody partial
, która istnieje na każdym urządzeniu partial
.
// @-? is an infix type alias for PLens
val someCash: Pocket @-? Cash = cash.partial andThen somePLens
scala> someCash.get(Pocket(Some(Cash("zilch"))))
res1: Option[Cash] = Some(Cash(zilch))
W ten sam sposób możemy stworzyć naszą częściowy obiektyw oglądania pieniężnych posiadanych przez Person
przez komponowanie wszystkie partial
wystąpień naszych soczewek i umieszczając wystąpień somePLens
. Tutaj użyłem operatora <=<
, aliasu dla andThen
(co jest równoważne compose
z włączonymi operandami).
val someCashValue: Person @-? String =
pants.partial <=< somePLens <=<
pocket.partial <=< somePLens <=<
cash.partial <=< somePLens <=<
value.partial
Tworzenie instancji Person
grać z:
val ben = Person(Some(Pants(Some(Pocket(Some(Cash("zilch")))))))
Stosując obiektyw częściowy dostęp do wartości pieniężnych mam:
scala> someCashValue.get(ben)
res2: Option[String] = Some(zilch)
Stosując obiektyw częściowej modyfikacji wartości :
scala> someCashValue.mod(_ + ", zero, nada", ben)
res3: Person = Person(Some(Pants(Some(Pocket(Some(Cash(zilch, zero, nada)))))))
(!) 0
Teraz, gdy jestem nie sobie jakieś spodnie, możemy zobaczyć, jak próbą zmodyfikować wartość mojego gotówce będzie miała żadnego wpływu:
scala> val ben = Person(None)
ben: Person = Person(None)
scala> someCashValue.mod(_ + ", zero, nada", ben)
res4: Person = Person(None)
Niesamowite, dzięki! Podejście dla zrozumienia jest właściwie dokładnie tym, co próbowałem zrobić, ale struktura, z którą pracuję, nie jest tak czysta jak przykład, który podałem powyżej. Przynajmniej to potwierdza, że jestem na dobrej drodze. –