Неявные параметры
Передача контекста
«Неявные параметры» — бесплатный урок 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 — локальная установка не требуется.
Все уроки этого курса
- Неявные параметры
- Scala 3 given/using
- Неявные преобразования
- Методы-расширения