Typy sumy i przecięcia
Nowe funkcje typów
Typy sumy i przecięcia 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.
Nowe funkcje systemu typów
Scala 3 dodaje do systemu typów typy sumy (A | B) oraz typy przecięcia (A & B). Pozwalają one precyzyjniej opisywać wartości bez tworzenia hierarchii dziedziczenia.
object Main:
def main(args: Array[String]): Unit =
println("Union: A | B, Intersection: A & B")Podstawy typów sumy
Typ sumy A | B reprezentuje wartość, która jest typu A albo B. Jest to teoriomnogościowa alternatywa OR dla typów.
object Main:
def show(x: Int | String): String = x match
case i: Int => s"int $i"
case s: String => s"str $s"
def main(args: Array[String]): Unit =
println(show(42))
println(show("hi"))Typy sumy nie wymagają wspólnego nadtypu
W przeciwieństwie do Either w Scala 2 typy sumy nie wymagają opakowywania. Dowolne dwa typy można połączyć w sumę, nawet jeśli nie mają wspólnej klasy nadrzędnej.
object Main:
def parse(input: Int | Boolean): String =
input match
case n: Int => s"number $n"
case b: Boolean => s"flag $b"
def main(args: Array[String]): Unit =
println(parse(7))
println(parse(true))Typy sumy do modelowania błędów
Typy sumy są przydatne do modelowania prostych wyników zakończonych błędem bez używania typu opakowującego. W połączeniu z enumami lub singletonami pozostają czytelne.
case object NotFound
object Main:
def lookup(id: Int): String | NotFound.type =
if id == 1 then "Alice" else NotFound
def main(args: Array[String]): Unit =
println(lookup(1))
println(lookup(2))Podstawy typów przecięcia
Typ przecięcia A & B reprezentuje wartość, która jest jednocześnie typu A i B. Jest to teoriomnogościowa koniunkcja AND, często używana do łączenia cech.
trait Named:
def name: String
trait Aged:
def age: Int
object Main:
def describe(p: Named & Aged): String =
s"${p.name} is ${p.age}"
def main(args: Array[String]): Unit =
val person = new Named with Aged:
def name = "Bob"
def age = 40
println(describe(person))Przemienność przecięcia
Kolejność nie ma znaczenia w przypadku typów przecięcia: A & B jest tym samym typem co B & A. Różni się to od typów złożonych A with B w Scala 2, w których kolejność wpływała na rozwiązywanie niektórych składowych.
trait Readable:
def read: String
trait Writable:
def write(s: String): Unit
object Main:
def use(r: Readable & Writable): Unit =
r.write("x")
println(r.read)
def main(args: Array[String]): Unit =
val rw = new Readable with Writable:
def read = "data"
def write(s: String) = println(s"wrote $s")
use(rw)Łączenie wielu cech
Można przeciąć więcej niż dwa typy. Wynik wymaga wszystkich wymienionych możliwości.
trait A: def a: Int
trait B: def b: Int
trait C: def c: Int
object Main:
def sum(x: A & B & C): Int = x.a + x.b + x.c
def main(args: Array[String]): Unit =
val v = new A with B with C:
def a = 1
def b = 2
def c = 3
println(sum(v))Aliasy typów sumy
Długim typom sumy można nadać nazwę za pomocą aliasu type, aby zachować czytelność sygnatur.
type Json = Int | String | Boolean
object Main:
def render(j: Json): String = j match
case i: Int => i.toString
case s: String => s"\"$s\""
case b: Boolean => b.toString
def main(args: Array[String]): Unit =
println(render("hi"))
println(render(true))Kompletne dopasowywanie typów sumy
Kompilator zna składowe sumy, więc może sprawdzać kompletność dopasowania. Obsłużenie każdej alternatywy sprawia, że dopasowanie jest zupełne.
type Shape = "circle" | "square"
object Main:
def sides(s: Shape): Int = s match
case "circle" => 0
case "square" => 4
def main(args: Array[String]): Unit =
println(sides("square"))Rozszerzanie typów sumy
Po przypisaniu wartości typu sumy do zmiennej, której typ jest wywnioskowany, Scala zachowuje typ sumy. Należy jednak pamiętać, że niektóre operacje rozszerzają typ do najmniejszego wspólnego nadtypu, dlatego warto użyć adnotacji, jeśli typ sumy ma zostać zachowany.
object Main:
def pick(flag: Boolean): Int | String =
if flag then 1 else "one"
def main(args: Array[String]): Unit =
val x: Int | String = pick(false)
println(x)Kiedy używać poszczególnych typów
Proszę wybrać właściwe narzędzie.
- Suma: wartość jest jednym z kilku typów (OR).
- Przecięcie: wartość jednocześnie spełnia wymagania kilku cech (AND).
- Typy sumy pozwalają uniknąć typów opakowujących, a typy przecięcia — głębokiego dziedziczenia.
trait Logger: def log(s: String): Unit
trait Clock: def now: Long
object Main:
def run(env: Logger & Clock): Unit =
env.log(s"time=${env.now}")
def main(args: Array[String]): Unit =
val env = new Logger with Clock:
def log(s: String) = println(s)
def now = 100L
run(env)Szybkie sprawdzenie
Sprawdź swoją wiedzę na temat typów sumy i przecięcia.
Podsumowanie
Poznał(a) Pan/Pani typy sumy i przecięcia w Scala 3.
A | B: wartość jest typu A albo B, bez potrzeby używania opakowania lub wspólnego nadtypu.A & B: wartość jest jednocześnie typu A i B; operacja jest przemienna.- Używaj dopasowania wzorców do zawężania typów sumy, a typów przecięcia do łączenia cech.
- Używaj aliasów
type, aby nadawać nazwy długim typom sumy.
object Main:
def length(x: String | List[Int]): Int = x match
case s: String => s.length
case l: List[Int] => l.length
def main(args: Array[String]): Unit =
println(length("hello"))
println(length(List(1, 2, 3)))Często zadawane pytania
Czy lekcja „Typy sumy i przecięcia” jest bezpłatna?
Tak — pełny tekst „Typy sumy i przecięcia” 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 „Typy sumy i przecięcia”?
Nowe funkcje typów Ć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 „Typy sumy i przecięcia”?
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
- Znaczące wcięcia
- Enumy w Scali 3
- Typy niejawne
- Typy sumy i przecięcia