Scala for Backend Engineering & Functional Programming · Lekcja

Własne kodeki

Obsłuży Pan/Pani nietypowe struktury.

Lekcja 4 z 413 kroki

Własne kodeki to bezpłatna lekcja Scala for Backend Engineering & Functional Programming na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Scala for Backend Engineering & Functional Programming, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Scala for Backend Engineering & Functional Programming zawiera 4 lekcji w sumie.

Kiedy potrzebny jest własny kodek

Wyprowadzanie obsługuje typowe przypadki, ale czasami JSON nie odzwierciedla klasy przypadku: może używać starszych nazw pól, kodowanych wyliczeń lub formatów takich jak znaczniki czasu.

Wtedy należy ręcznie napisać obiekt Decoder, Encoder albo oba.

Dekoder z kursora

Najbardziej jawnym sposobem utworzenia dekodera jest użycie Decoder.instance, który otrzymuje obiekt HCursor.

Po polach porusza się za pomocą downField i as, zwracając wartość Either.

import io.circe.Decoder

case class User(name: String, age: Int)
implicit val dec: Decoder[User] = Decoder.instance { c =>
  for {
    n <- c.downField("full_name").as[String]
    a <- c.downField("years").as[Int]
  } yield User(n, a)
}

Pomocnicze metody forProductN

W przypadku prostych mapowań bardziej zwięzła jest metoda Decoder.forProduct2: należy podać klucze JSON i przekazać konstruktor.

Pomocnicze metody są dostępne od forProduct1 aż po wersje obsługujące wiele argumentów.

import io.circe.Decoder

implicit val dec: Decoder[User] =
  Decoder.forProduct2("full_name", "years")(User.apply)

Ręczne tworzenie enkodera

Odwzoruj dekoder za pomocą Encoder.instance, tworząc obiekt Json z pól.

Możesz też użyć Encoder.forProduct2, aby jednym wywołaniem zmapować wartości z powrotem na wybrane klucze JSON.

import io.circe.Encoder

implicit val enc: Encoder[User] =
  Encoder.forProduct2("full_name", "years")(u =>
    (u.name, u.age))

Przekształcanie istniejących kodeków

Rzadko zaczyna się od zera. map dostosowuje wynik dekodera, a contramap dostosowuje dane wejściowe enkodera.

emap działa podobnie jak map, ale może zakończyć się niepowodzeniem, zwracając Either[String, A] do celów walidacji.

import io.circe.Decoder

case class Age(value: Int)
implicit val dec: Decoder[Age] =
  Decoder[Int].emap { i =>
    if (i >= 0) Right(Age(i)) else Left("negative age")
  }

Kodeki dla wyliczeń

Zapieczętowane cechy z obiektami przypadku służą do modelowania wyliczeń. Każdy przypadek należy zakodować jako ciąg znaków będący etykietą, a podczas dekodowania dopasować z powrotem ten ciąg.

emap zamienia nieznaną etykietę w czytelny błąd dekodowania.

sealed trait Role
case object Admin extends Role
case object Guest extends Role

implicit val dec: Decoder[Role] = Decoder[String].emap {
  case "admin" => Right(Admin)
  case "guest" => Right(Guest)
  case other   => Left(s"unknown role: $other")
}

Ponowne kodowanie wyliczenia

Połącz dekoder wyliczenia z enkoderem używającym contramap, który renderuje każdy przypadek jako jego etykietę.

Teraz zapieczętowana cecha jest kodowana i dekodowana bez utraty informacji jako zwykły ciąg znaków w JSON.

import io.circe.Encoder

implicit val enc: Encoder[Role] = Encoder[String].contramap {
  case Admin => "admin"
  case Guest => "guest"
}

Własny kodek dla dat

Circe nie zawiera wbudowanych kodeków java.time w module core, dlatego daty są klasycznym przypadkiem zastosowania własnego kodeka.

Dekoduj i koduj za pomocą formatu ciągu ISO.

import java.time.LocalDate
import io.circe.{Decoder, Encoder}

implicit val dec: Decoder[LocalDate] =
  Decoder[String].map(LocalDate.parse)
implicit val enc: Encoder[LocalDate] =
  Encoder[String].contramap(_.toString)

Łączenie w kodek

Gdy masz oba kierunki, połącz je w jeden obiekt Codec[A] za pomocą Codec.from(decoder, encoder).

Dzięki temu w zakresie wystarczy jeden implicit zamiast dwóch osobnych.

import io.circe.Codec

implicit val roleCodec: Codec[Role] =
  Codec.from(dec, enc)

Dyskryminatory dla ADT

W przypadku zapieczętowanych hierarchii zawierających dane biblioteka circe-generic-extras dodaje pole dyskryminatora zamiast obiektu opakowującego.

Skonfiguruj je raz, a następnie wyprowadź kodeki dla całego ADT.

import io.circe.generic.extras._

implicit val cfg: Configuration =
  Configuration.default.withDiscriminator("type")

@ConfiguredJsonCodec sealed trait Shape
@ConfiguredJsonCodec case class Circle(r: Double) extends Shape

Zakres i priorytet implicitów

Ręcznie napisany implicit kodeka ma pierwszeństwo przed wyprowadzaniem, o ile znajduje się w zakresie. Umieść go w obiekcie towarzyszącym, aby zawsze był znajdowany.

Unikaj jednoczesnego importowania auto._ i ręcznej instancji dla tego samego typu, aby zapobiec niejednoznaczności.

Szybki test

Sprawdź swoją wiedzę na temat własnych kodeków.

Podsumowanie

Własne kodeki obsługują JSON, który nie pasuje do typów. Twórz je za pomocą Decoder.instance, forProductN albo przekształcaj istniejące kodeki za pomocą map, contramap i emap.

Wyliczenia i daty to częste przypadki; połącz oba kierunki za pomocą Codec.from, a dla ADT używaj dyskryminatorów.

Bezpłatny start

Ucz się Scala dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
39
Lekcje
143

Często zadawane pytania

Czy lekcja „Własne kodeki” jest bezpłatna?

Tak — pełny tekst „Własne kodeki” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Scala for Backend Engineering & Functional Programming, przejdź na CoddyKit PRO. Kurs Scala for Backend Engineering & Functional Programming zawiera 4 lekcji w sumie.

Co nauczysz się w „Własne kodeki”?

Obsłuży Pan/Pani nietypowe struktury. Ćwiczysz Scala for Backend Engineering & Functional Programming z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Scala for Backend Engineering & Functional Programming?

Nie wymagamy żadnego doświadczenia. Scala for Backend Engineering & Functional Programming w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Własne kodeki”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Scala for Backend Engineering & Functional Programming?

Tak. Każda lekcja Scala for Backend Engineering & Functional Programming zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Parsowanie JSON
  2. Dekodowanie do case class
  3. Kodowanie do JSON
  4. Własne kodeki
← Powrót do Scala for Backend Engineering & Functional Programming