Неявные (implicit) параметры и преобразования в Scala

в 17:20, , рубрики: implicit, scala, Программирование, функциональное программирование

Пробежавшись по предыдущим статьям на Хабре, тыц и тыц так и не удалось в быстром режиме понять, что делает неявность (implicit) в Scala. Попробуем разобраться вместе.

Неявные (implicit) параметры и преобразования в Scala - 1

Итак, implicit в Scala позволяют избежать вызывания методов или явных ссылок на переменные, и взамен этого позволяют компилятору самому найти нужные неявные данные.

Например, мы могли бы написать функцию для преобразования из Float в Int(FloatToInt) и, вместо того, чтобы вызвать эту функцию явно, компилятор бы сделал это вместо нас неявно:

def double(value: Int) = value * 2
implicit def FloatToInt(value: Float):Int = value.toInt
println(double(2.5F))

Запутанно? Давайте обо всём по порядку.

Итак, сегодня мы рассмотрим две категории implicit, а именно:

  • Неявные параметры (implicit parameters, values). Они являются автоматически переданными компилятором значениями, объявленными через implicit.
  • Неявное преобразование (implicit conversion). При несовпадении типа ожидаемого параметра с входящим параметром компилятор ищет любой метод в области видимости, отмеченный implicit и с нужными в данной ситуации ожидаемым параметром и входящим параметром и автоматически его передаёт.

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

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

Например, такая функция, принимающая на вход неявный параметр value и удваивающая его:

def double(implicit value: Int) = value * 2

Без неявного параметра упадёт с ошибкой:

def double(implicit value: Int) = value * 2
println(double) // error: could not find implicit value for parameter value

С переданным явно параметром сработает:

def double(implicit value: Int) = value * 2
println(double(3))  // 6

С неявным параметром это будет выглядеть так:

def double(implicit value: Int) = value * 2
implicit val multiplier = 2
println(double) // 4

Но нужно быть аккуратным:

def double(implicit value: Int) = value * 2
implicit val multiplier = 2
implicit val multiplier2 = 1 
println(double) // error: ambiguous implicit values

И напоследок пример с передачей в качестве неявного параметра def:

def double(implicit value: Int) = value * 2
val cappucinoLarge: Boolean = false
implicit def cappucinoPrice: Int = if (cappucinoLarge) 200 else 100
println(double) // 200

Т.е. в итоге у нас получится

double(cappucinoPrice())

Примечания по синтаксису:


def func1(implicit value1: Int)                          // value1 неявно
def func2(implicit value1: Int, value2: Int)             // value1 и value2 неявны
def func3(value1: Int, implicit value2: Int)             // ошибка компиляции
def func4(value1: Int)(implicit value2: Int)             // только value2 неявно
def func5(implicit value1: Int)(value2: Int)             // ошибка компиляции
def func6(implicit value1: Int)(implicit value2: Int)    // ошибка компиляции

Неявное преобразование

Возвращаясь к примеру из Float в Int:

def double(value: Int) = value * 2
implicit def FloatToInt(value: Float):Int = value.toInt
println(double(2.5F))

При вызове double у нас происходит несовпадение типа ожидаемого параметра (Int) с входящим параметром (Float). Поэтому компилятор ищет любой метод в области видимости, отмеченный implicit и с нужными в данной ситуации ожидаемым параметром (Int) и входящим параметром (Float). Находит FloatToInt, производит преобразование и передает дальше нужное значение в double.

Теперь, надеюсь, стало понятнее. Всем успехов в освоении Scala!

Автор: Кузьма Лешаков

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js