Algebraiczne typy danych
Modelowanie domeny
Algebraiczne typy danych to bezpłatna lekcja Scala for Backend Engineering & Functional Programming na CoddyKit. To lekcja 3 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.
Czym jest ADT?
Algebraiczny typ danych (ADT) to typ utworzony przez połączenie innych typów. W Scali modeluje się ADT za pomocą sealed trait oraz wariantów case class i case object.
ADT pozwalają precyzyjnie opisywać strukturę danych domeny.
Typy sum
Typ sum oznacza, że wartość jest jedną z kilku możliwości (LUB). Sygnalizator świetlny jest czerwony LUB żółty LUB zielony.
Wyraża się to za pomocą sealed trait i kilku wariantów.
sealed trait Light
case object Red extends Light
case object Yellow extends Light
case object Green extends Light
object Main {
def main(args: Array[String]): Unit = {
val l: Light = Yellow
println(l)
}
}Typy iloczynowe
Typ iloczynowy oznacza, że wartość łączy kilka pól (ORAZ). Punkt ma współrzędną x ORAZ współrzędną y.
Case classes są typami iloczynowymi.
case class Point(x: Int, y: Int)
object Main {
def main(args: Array[String]): Unit = {
val p = Point(3, 4)
println(s"${p.x} and ${p.y}")
}
}Łączenie typów sum i iloczynów
Rzeczywiste ADT łączą oba rodzaje: sealed trait (suma), którego wariantami są case classes (iloczyny).
W tym przypadku Shape to Circle (z promieniem) LUB Rectangle (z szerokością i wysokością).
sealed trait Shape
case class Circle(radius: Double) extends Shape
case class Rectangle(w: Double, h: Double) extends Shape
object Main {
def main(args: Array[String]): Unit = {
val s: Shape = Rectangle(3, 4)
println(s)
}
}Operowanie na ADT
ADT przetwarza się przez dopasowywanie wzorców do jego wariantów. Każda gałąź obsługuje jeden kształt.
sealed trait Shape
case class Circle(radius: Double) extends Shape
case class Rectangle(w: Double, h: Double) extends Shape
object Main {
def area(s: Shape): Double = s match {
case Circle(r) => 3.14159 * r * r
case Rectangle(w, h) => w * h
}
def main(args: Array[String]): Unit = {
println(area(Circle(2)))
println(area(Rectangle(3, 4)))
}
}Modelowanie domeny
ADT sprawiają, że nieprawidłowych stanów nie da się reprezentować. Zamodeluj metodę płatności jako zamknięty zbiór prawidłowych opcji.
sealed trait PaymentMethod
case class CreditCard(number: String) extends PaymentMethod
case class BankTransfer(iban: String) extends PaymentMethod
case object Cash extends PaymentMethod
object Main {
def main(args: Array[String]): Unit = {
val m: PaymentMethod = Cash
println(m)
}
}Rekurencyjne ADT
ADT może odwoływać się do samego siebie, co pozwala modelować drzewa i listy. Oto proste drzewo binarne.
sealed trait Tree
case object Leaf extends Tree
case class Node(value: Int, left: Tree, right: Tree) extends Tree
object Main {
def main(args: Array[String]): Unit = {
val t: Tree = Node(1, Leaf, Node(2, Leaf, Leaf))
println(t)
}
}Składanie rekurencyjnego ADT
Rekurencja wraz z dopasowywaniem pozwala przetwarzać całą strukturę. Tutaj sumujemy wszystkie wartości w drzewie.
sealed trait Tree
case object Leaf extends Tree
case class Node(value: Int, left: Tree, right: Tree) extends Tree
object Main {
def sum(t: Tree): Int = t match {
case Leaf => 0
case Node(v, l, r) => v + sum(l) + sum(r)
}
def main(args: Array[String]): Unit = {
val t = Node(1, Node(2, Leaf, Leaf), Node(3, Leaf, Leaf))
println(sum(t))
}
}Dlaczego ADT?
ADT są tak przydatne, ponieważ:
- Precyzyjnie opisują dane jako sumy i iloczyny
- Uniemożliwiają konstruowanie nieprawidłowych stanów
- Doskonale współpracują z wyczerpującym dopasowywaniem wzorców
- Skalują się do struktur rekurencyjnych, takich jak drzewa i listy
ADT a dziedziczenie
Tradycyjne OOP rozpraszałoby zachowanie pomiędzy podklasami. ADT utrzymują zamknięte definicje danych, a zachowanie umieszczają w funkcjach dopasowujących wzorce.
To rozdzielenie danych i zachowania jest cechą charakterystyczną projektowania funkcyjnego.
Połączenie wszystkiego
Kompletny, niewielki ADT z funkcją obsługującą każdy wariant.
sealed trait Json
case class JNum(n: Double) extends Json
case class JStr(s: String) extends Json
case object JNull extends Json
object Main {
def render(j: Json): String = j match {
case JNum(n) => n.toString
case JStr(s) => "\"" + s + "\""
case JNull => "null"
}
def main(args: Array[String]): Unit = {
List(JNum(3.0), JStr("hi"), JNull).foreach(j => println(render(j)))
}
}Szybkie sprawdzenie
Sprawdź, jak rozumiesz ADT.
Podsumowanie
Dowiedziałeś się, jak tworzyć algebraiczne typy danych:
- Typy sum: sealed trait z wieloma wariantami (LUB)
- Typy iloczynowe: case classes z polami (ORAZ)
- Łącz je, aby precyzyjnie modelować domeny
- ADT mogą być rekurencyjne (drzewa, listy)
- Przetwarzaj je za pomocą dopasowywania wzorców
Często zadawane pytania
Czy lekcja „Algebraiczne typy danych” jest bezpłatna?
Tak — pełny tekst „Algebraiczne typy danych” 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 „Algebraiczne typy danych”?
Modelowanie domeny Ć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 3 z 4.
Ile czasu zajmuje lekcja „Algebraiczne typy danych”?
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
- Klasy case
- Cechy sealed
- Algebraiczne typy danych
- Wyczerpujące dopasowywanie