Scala for Backend Engineering & Functional Programming · Lekcja

Konwersje niejawne

Używaj ostrożnie

Lekcja 3 z 413 kroki

Konwersje niejawne 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 konwersja niejawna?

Konwersja niejawna automatycznie przekształca wartość jednego typu na inny, gdy kompilator tego potrzebuje. Może ułatwiać korzystanie z API, ale należy używać jej ostrożnie, ponieważ ukrywa przebieg operacji.

object Main {
  import scala.language.implicitConversions
  implicit def intToString(x: Int): String = s"number-$x"
  def main(args: Array[String]): Unit = {
    val s: String = 42
    println(s)
  }
}

Jak kompilator ich używa

Gdy typ wartości nie pasuje do oczekiwanego typu, kompilator wyszukuje konwersję niejawną, która usuwa tę niezgodność, i po cichu ją wstawia.

object Main {
  import scala.language.implicitConversions
  implicit def doubleToInt(d: Double): Int = d.toInt
  def addTen(x: Int): Int = x + 10
  def main(args: Array[String]): Unit = {
    println(addTen(3.9))
  }
}

Włączanie tej funkcji

Definiowanie konwersji niejawnych wymaga zaimportowania scala.language.implicitConversions; w przeciwnym razie kompilator wyświetli ostrzeżenie. To celowe utrudnienie ma zniechęcać do nadużywania tej funkcji.

object Main {
  import scala.language.implicitConversions
  case class Celsius(value: Double)
  implicit def doubleToCelsius(d: Double): Celsius = Celsius(d)
  def describe(c: Celsius): String = s"${c.value} C"
  def main(args: Array[String]): Unit = {
    println(describe(36.6))
  }
}

Opakowywanie w celu dodania metod (stary styl)

Przed wprowadzeniem metod rozszerzających konwersje niejawne do klasy opakowującej były sposobem na „dodawanie” metod do istniejących typów — był to tak zwany wzorzec pimp-my-library.

object Main {
  import scala.language.implicitConversions
  class RichInt2(x: Int) {
    def squared: Int = x * x
  }
  implicit def toRich(x: Int): RichInt2 = new RichInt2(x)
  def main(args: Array[String]): Unit = {
    println(5.squared)
  }
}

Niebezpieczeństwo: ciche niespodzianki

Ponieważ konwersje są niewidoczne w miejscu wywołania, mogą powodować mylące zachowanie i błędy trudne do prześledzenia. Literówka może się skompilować, przypadkowo uruchamiając konwersję.

object Main {
  import scala.language.implicitConversions
  implicit def boolToInt(b: Boolean): Int = if (b) 1 else 0
  def main(args: Array[String]): Unit = {
    val total = true + 4 // surprising! becomes 1 + 4
    println(total)
  }
}

Preferowanie jawnych konwersji

Często najbezpieczniejszym wyborem jest zwykła nazwana metoda zamiast konwersji niejawnej. Kod jest dłuższy, ale jego działanie jest oczywiste dla czytających.

object Main {
  case class Celsius(value: Double)
  def fromDouble(d: Double): Celsius = Celsius(d)
  def main(args: Array[String]): Unit = {
    val c = fromDouble(20.5)
    println(c)
  }
}

Scala 3: klasa typów Conversion

Scala 3 uwidacznia konwersje za pomocą instancji given Conversion[A, B]. Zamiar jest dzięki temu czytelniejszy, a import językowy nadal jest wymagany.

import scala.language.implicitConversions

object Main:
  given Conversion[Int, String] = (x: Int) => s"val-$x"
  def main(args: Array[String]): Unit =
    val s: String = 7
    println(s)

Konwersje są stosowane tylko raz

Kompilator stosuje najwyżej jedną konwersję niejawną naraz. Nie łączy dwóch konwersji w celu usunięcia niezgodności, co ogranicza liczbę niespodzianek.

object Main {
  import scala.language.implicitConversions
  implicit def intToStr(x: Int): String = x.toString
  def needString(s: String): Int = s.length
  def main(args: Array[String]): Unit = {
    println(needString(12345))
  }
}

Gdzie wyszukiwane są konwersje

Podobnie jak inne wartości niejawne, konwersje są rozpoznawane w zakresie lokalnym, w importach i w obiektach towarzyszących. Umieszczenie ich w jasno nazwanym imporcie sprawia, że ich obecność jest widoczna.

object Conversions:
  import scala.language.implicitConversions
  implicit def strToLen(s: String): Int = s.length

object Main:
  import Conversions._
  def main(args: Array[String]): Unit =
    val n: Int = "hello"
    println(n)

Kiedy konwersje mają sens

Uzasadnione zastosowania obejmują współpracę z typami Javy, pomocnicze funkcje rozszerzania typów liczbowych oraz granice bibliotek. Poza tymi przypadkami należy preferować metody rozszerzające lub jawne funkcje.

object Main {
  import scala.language.implicitConversions
  case class Meters(v: Double)
  implicit def metersToDouble(m: Meters): Double = m.v
  def main(args: Array[String]): Unit = {
    val d: Double = Meters(3.5)
    println(d * 2)
  }
}

Praktyczna zasada

Jeśli czytający nie może wywnioskować z kodu, że zachodzi konwersja, jest to sygnał ostrzegawczy. Po konwersje niejawne należy sięgać na końcu, dopiero po metodach rozszerzających i jawnych wywołaniach.

object Main {
  // Explicit and obvious - usually better
  case class Price(cents: Int)
  def toDollars(p: Price): Double = p.cents / 100.0
  def main(args: Array[String]): Unit = {
    println(toDollars(Price(1599)))
  }
}

Szybkie sprawdzenie

Jakie jest główne zagrożenie związane z konwersjami niejawnymi?

Podsumowanie

Opanował(a) Pan/Pani konwersje niejawne i związane z nimi ograniczenia:

  • Automatycznie konwertują jeden typ na inny, gdy typy się nie zgadzają
  • Wymagają użycia import scala.language.implicitConversions
  • Scala 3 używa given Conversion[A, B]
  • Jednocześnie stosowana jest tylko jedna konwersja
  • Należy używać ich oszczędnie; lepiej preferować metody rozszerzające lub jawne wywołania
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 „Konwersje niejawne” jest bezpłatna?

Tak — pełny tekst „Konwersje niejawne” 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 „Konwersje niejawne”?

Używaj ostrożnie Ć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 „Konwersje niejawne”?

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. Parametry niejawne
  2. Scala 3 given/using
  3. Konwersje niejawne
  4. Metody rozszerzające
← Powrót do Scala for Backend Engineering & Functional Programming