Definiowanie instancji
Instancje niejawne
Definiowanie instancji to bezpłatna lekcja Scala for Backend Engineering & Functional Programming na CoddyKit. To lekcja 2 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.
Definiowanie instancji
Instancja informuje kompilator, jak klasa typów zachowuje się dla określonego typu. W Scali instancje zwykle oznacza się jako implicit (Scala 2) albo deklaruje za pomocą given (Scala 3), aby były znajdowane automatycznie.
Instancja implicit val
W przypadku prostej klasy typów wystarczy implicit val. Kompilator znajdzie ją, gdy funkcja będzie potrzebować Show[Int].
trait Show[A] { def show(a: A): String }
object Main {
implicit val intShow: Show[Int] = (a: Int) => s"Int=$a"
def display[A](a: A)(implicit s: Show[A]): String = s.show(a)
def main(args: Array[String]): Unit = {
println(display(123))
}
}implicitly: pobieranie instancji
implicitly[Show[Int]] prosi kompilator o pobranie instancji dostępnej w bieżącym zakresie. Jest to przydatne do sprawdzania, czy instancja istnieje, albo do bezpośredniego uzyskania do niej dostępu.
trait Show[A] { def show(a: A): String }
object Main {
implicit val intShow: Show[Int] = (a: Int) => s"<$a>"
def main(args: Array[String]): Unit = {
val s = implicitly[Show[Int]]
println(s.show(8))
}
}Instancje dla własnych typów
Zdefiniuj instancję dla własnej klasy case. Klasa danych pozostaje przejrzysta, a formatowanie znajduje się w instancji.
trait Show[A] { def show(a: A): String }
case class Point(x: Int, y: Int)
object Main {
implicit val pointShow: Show[Point] = (p: Point) => s"(${p.x}, ${p.y})"
def display[A](a: A)(implicit s: Show[A]): String = s.show(a)
def main(args: Array[String]): Unit = {
println(display(Point(3, 4)))
}
}implicit def dla instancji generycznych
Gdy instancja zależy od innej instancji, użyj implicit def. W tym przypadku Show[List[A]] jest tworzone na podstawie Show[A].
trait Show[A] { def show(a: A): String }
object Main {
implicit val intShow: Show[Int] = (a: Int) => a.toString
implicit def listShow[A](implicit s: Show[A]): Show[List[A]] =
(xs: List[A]) => xs.map(s.show).mkString("[", ", ", "]")
def display[A](a: A)(implicit s: Show[A]): String = s.show(a)
def main(args: Array[String]): Unit = {
println(display(List(1, 2, 3)))
}
}Instancje w obiekcie towarzyszącym
Umieszczenie instancji w obiekcie towarzyszącym klasy typów sprawia, że są one znajdowane automatycznie, bez żadnego importu. Jest to zalecane miejsce dla domyślnych instancji.
trait Show[A] { def show(a: A): String }
object Show {
implicit val intShow: Show[Int] = (a: Int) => s"i:$a"
implicit val strShow: Show[String] = (a: String) => s"s:$a"
}
object Main {
def display[A](a: A)(implicit s: Show[A]): String = s.show(a)
def main(args: Array[String]): Unit = {
println(display(5))
println(display("hi"))
}
}Zakres i priorytet implicit
Kompilator szuka instancji w kilku miejscach: najpierw w zakresie lokalnym lub zaimportowanym, a następnie w obiektach towarzyszących zaangażowanych typów. Jeśli dwie instancje są równie szczegółowe, pojawi się błąd ambiguous implicit.
Skrócona składnia context bound
Składnia def f[A: Show](a: A) to context bound: oznacza, że w zakresie musi znajdować się niejawna instancja Show[A]. Wewnątrz funkcji można ją pobrać za pomocą implicitly.
trait Show[A] { def show(a: A): String }
object Main {
implicit val intShow: Show[Int] = (a: Int) => s"n=$a"
def display[A: Show](a: A): String = implicitly[Show[A]].show(a)
def main(args: Array[String]): Unit = {
println(display(77))
}
}Pomocnicza funkcja pobierająca
Biblioteki dodają do obiektu towarzyszącego metodę apply jako wygodny mechanizm pobierania instancji: Show[Int] zwraca instancję. Jest to czytelniejsze niż implicitly.
trait Show[A] { def show(a: A): String }
object Show {
def apply[A](implicit s: Show[A]): Show[A] = s
implicit val intShow: Show[Int] = (a: Int) => s"=$a"
}
object Main {
def main(args: Array[String]): Unit = {
println(Show[Int].show(10))
}
}Unikanie osieroconych instancji
Osierocona instancja to instancja zdefiniowana zarówno poza klasą typów, jak i poza typem. Jest dozwolona, ale może powodować niespójne zachowanie w zależności od importów. Preferuj instancje w obiektach towarzyszących, aby zachować spójność.
Połączenie wszystkich elementów
Kompletny program: instancje w obiekcie towarzyszącym, wyprowadzona instancja dla list oraz mechanizm pobierania instancji.
trait Show[A] { def show(a: A): String }
object Show {
def apply[A](implicit s: Show[A]): Show[A] = s
implicit val intShow: Show[Int] = _.toString
implicit def listShow[A](implicit s: Show[A]): Show[List[A]] =
(xs: List[A]) => xs.map(s.show).mkString(", ")
}
object Main {
def main(args: Array[String]): Unit = {
println(Show[List[Int]].show(List(4, 5, 6)))
}
}Szybkie sprawdzenie
Sprawdź swoją wiedzę na temat definiowania instancji.
Podsumowanie
Nauczyłeś się definiować instancje:
implicit valsłuży do prostych instancji, aimplicit defdo instancji wyprowadzanych.- Pobieraj instancje za pomocą
implicitlylub metodyapplyw obiekcie towarzyszącym. - Używaj context bounds
[A: Show]jako skróconej składni. - Umieszczaj instancje w obiektach towarzyszących, aby unikać osieroconych instancji.
Często zadawane pytania
Czy lekcja „Definiowanie instancji” jest bezpłatna?
Tak — pełny tekst „Definiowanie instancji” 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 „Definiowanie instancji”?
Instancje niejawne Ć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 2 z 4.
Ile czasu zajmuje lekcja „Definiowanie instancji”?
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
- Wzorzec type class
- Definiowanie instancji
- Typowe type classy
- Wyprowadzanie type class