0Pricing
Scala for Backend Engineering & Functional Programming · Урок

Неявные параметры

Передача контекста

«Неявные параметры» — бесплатный урок Scala for Backend Engineering & Functional Programming на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Scala for Backend Engineering & Functional Programming, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Scala for Backend Engineering & Functional Programming содержит 4 уроков всего.

Автоматическая передача контекста

Неявные параметры позволяют компилятору передать аргумент за Вас, выбрав его среди значений, помеченных как implicit в области видимости. Они отлично подходят для передачи общего контекста, например конфигурации или правил форматирования.

object Main {
  def greet(name: String)(implicit greeting: String): String =
    s"$greeting, $name!"
  implicit val defaultGreeting: String = "Hello"
  def main(args: Array[String]): Unit = {
    println(greet("Ann"))
  }
}

Список неявных параметров

Пометьте последний список параметров ключевым словом implicit. Если при вызове этот список опущен, компилятор ищет подходящее неявное значение.

object Main {
  def multiply(x: Int)(implicit factor: Int): Int = x * factor
  implicit val f: Int = 10
  def main(args: Array[String]): Unit = {
    println(multiply(5))
  }
}

Явная передача неявных параметров

Вы всегда можете передать неявный параметр явно, переопределив значение из текущей области видимости. Это удобно для отдельных случаев.

object Main {
  def multiply(x: Int)(implicit factor: Int): Int = x * factor
  implicit val f: Int = 10
  def main(args: Array[String]): Unit = {
    println(multiply(5))
    println(multiply(5)(2))
  }
}

Разрешение неявных параметров по типу

Компилятор сопоставляет неявные значения по типу, а не по имени. В области видимости должно находиться ровно одно подходящее неявное значение, иначе компиляция завершится ошибкой из-за неоднозначности или отсутствия значения.

object Main {
  case class Config(env: String)
  def run()(implicit cfg: Config): String = s"running in ${cfg.env}"
  implicit val cfg: Config = Config("prod")
  def main(args: Array[String]): Unit = {
    println(run())
  }
}

implicitly для получения значения

Вспомогательная функция implicitly[T] напрямую получает из области видимости неявное значение типа T, не требуя указывать имя параметра.

object Main {
  implicit val name: String = "Scala"
  def main(args: Array[String]): Unit = {
    val n = implicitly[String]
    println(n)
  }
}

Сокращённая запись ограничения контекста

Ограничение контекста [T: Ordering] — это сокращённая запись неявного параметра типа Ordering[T]. Такой синтаксис часто используется с классами типов.

object Main {
  def max[T: Ordering](a: T, b: T): T = {
    val ord = implicitly[Ordering[T]]
    if (ord.gt(a, b)) a else b
  }
  def main(args: Array[String]): Unit = {
    println(max(3, 7))
    println(max("apple", "pear"))
  }
}

Передача контекста через вызовы

Неявные параметры особенно полезны, когда многим функциям нужен один и тот же контекст. Достаточно один раз пометить его как неявный — и он автоматически передаётся через вложенные вызовы.

object Main {
  case class User(name: String)
  def log(msg: String)(implicit u: User): Unit =
    println(s"[${u.name}] $msg")
  def doWork()(implicit u: User): Unit = {
    log("started")
    log("finished")
  }
  implicit val current: User = User("admin")
  def main(args: Array[String]): Unit = {
    doWork()
  }
}

Где выполняется поиск неявных значений

Компилятор ищет неявные значения в локальной области видимости, в импортах и в сопутствующих объектах задействованных типов. Сопутствующие объекты — удобное место для значений по умолчанию.

object Main {
  case class Currency(symbol: String)
  object Currency {
    implicit val default: Currency = Currency("$")
  }
  def price(amount: Int)(implicit c: Currency): String = s"${c.symbol}$amount"
  def main(args: Array[String]): Unit = {
    println(price(50))
  }
}

Ошибки неоднозначности

Если в области видимости находятся два неявных значения одного типа, компилятор сообщает об ошибке неоднозначного неявного значения. Оставляйте не более одного значения каждого типа или передавайте нужное значение явно.

object Main {
  def label(x: Int)(implicit unit: String): String = s"$x$unit"
  implicit val unit: String = "px"
  def main(args: Array[String]): Unit = {
    // Only one implicit String in scope -> no ambiguity
    println(label(12))
  }
}

Поведение, похожее на значения по умолчанию

Неявные параметры дают контекстно-зависимые значения по умолчанию: один и тот же вызов функции может возвращать разные результаты в зависимости от того, какое неявное значение находится в области видимости.

object Main {
  def format(n: Double)(implicit decimals: Int): String =
    f"$n%.${decimals}f"
  implicit val d: Int = 2
  def main(args: Array[String]): Unit = {
    println(format(3.14159))
    println(format(3.14159)(4))
  }
}

Используйте неявные параметры умеренно

Неявные параметры обладают большой мощью, но при чрезмерном использовании могут затруднить понимание кода. Оставляйте их для действительно общего контекста, например контекстов выполнения, конфигураций и экземпляров классов типов.

object Main {
  case class Locale(code: String)
  def hello()(implicit loc: Locale): String =
    if (loc.code == "tr") "Merhaba" else "Hello"
  implicit val loc: Locale = Locale("tr")
  def main(args: Array[String]): Unit = {
    println(hello())
  }
}

Быстрая проверка

Как компилятор решает, какое значение передать для неявного параметра?

Итоги

Вы изучили неявные параметры (в стиле Scala 2):

  • Пометьте список параметров как implicit, чтобы он заполнялся автоматически
  • Разрешение выполняется по типу, который должен быть уникальным в области видимости
  • implicitly[T] получает значение; ограничения контекста [T: TC] являются сокращённой записью
  • Поиск охватывает локальную область видимости, импорты и сопутствующие объекты
  • Используйте их для общего контекста, а не повсеместно

Часто задаваемые вопросы

Урок «Неявные параметры» бесплатный?

Да — полный текст урока «Неявные параметры» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Scala for Backend Engineering & Functional Programming, подпишись на CoddyKit PRO. Курс Scala for Backend Engineering & Functional Programming содержит 4 уроков всего.

Чему я научусь в уроке «Неявные параметры»?

Передача контекста Ты практикуешь Scala for Backend Engineering & Functional Programming с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Scala for Backend Engineering & Functional Programming?

Предыдущий опыт не требуется. Scala for Backend Engineering & Functional Programming на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Неявные параметры»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Scala for Backend Engineering & Functional Programming?

Да. Каждый урок Scala for Backend Engineering & Functional Programming включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Неявные параметры
  2. Scala 3 given/using
  3. Неявные преобразования
  4. Методы-расширения
← Назад к Scala for Backend Engineering & Functional Programming