0Pricing
Scala for Backend Engineering & Functional Programming · Lekcja

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 val służy do prostych instancji, a implicit def do instancji wyprowadzanych.
  • Pobieraj instancje za pomocą implicitly lub metody apply w 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

  1. Wzorzec type class
  2. Definiowanie instancji
  3. Typowe type classy
  4. Wyprowadzanie type class
← Powrót do Scala for Backend Engineering & Functional Programming