scalabook

Форк
0
/
ca-implicit-conversions.md 
112 строк · 5.6 Кб

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

Неявные преобразования определяются экземплярами given

класса scala.Conversion
. Этот класс определен в пакете scala
следующим образом:

abstract class Conversion[-T, +U] extends (T => U):
def apply (x: T): U

Например, без учета возможных ошибок преобразования, этот код определяет неявное преобразование из String

в Int
:

given Conversion[String, Int] with
def apply(s: String): Int = Integer.parseInt(s)

Используя псевдоним, можно выразиться более кратко:

given Conversion[String, Int] = Integer.parseInt(_)

Используя любое из этих преобразований, теперь String

можно использовать в местах, где ожидается Int
:

import scala.language.implicitConversions
// метод, который ожидает Int
def plus1(i: Int) = i + 1
// можно передать строку, которая преобразуется в Int
plus1("1")

Обратите внимание на предложение import scala.language.implicitConversions

в начале, чтобы разрешить неявные преобразования в файле.

Неявное преобразование автоматически применяется компилятором в трех случаях:

  1. Если выражение e
    имеет тип T
    и T
    не соответствует ожидаемому типу выражения S
    .
  2. В выборе e.m
    с e
    типа T
    , но T
    не определяет член m
    .
  3. В приложении e.m(args)
    с e
    типа T
    , если T
    определяет некоторые элементы с именем m
    , но ни один из этих членов не может быть применен к аргументам args
    .

В первом случае компилятор ищет given экземпляр scala.Conversion

, который сопоставляет аргумент типа T
с типом S
. Во втором и третьем случаях он ищет given экземпляр scala.Conversion
, который сопоставляет аргумент типа T
с типом, определяющим член m
, к которому можно применить args
, если они присутствуют. Если такой экземпляр C
найден, выражение e
заменяется на C.apply(e)
.

Примеры

  1. Пакет Predef
    содержит преобразования «автоматического упаковывания», которые сопоставляют примитивные числовые типы с подклассами java.lang.Number
    . Например, преобразование из Int
    в java.lang.Integer
    можно определить следующим образом:
given int2Integer: Conversion[Int, java.lang.Integer] =
java.lang.Integer.valueOf(_)
  1. Паттерн "magnet" иногда используется для выражения нескольких вариантов метода. Вместо того чтобы определять перегруженные версии метода, можно также позволить ему принимать один или несколько аргументов специально определенных "магнитных" типов, в которые могут быть преобразованы различные типы аргументов. Пример:
object Completions:
// The argument "magnet" type
enum CompletionArg:
case Error(s: String)
case Response(f: Future[HttpResponse])
case Status(code: Future[StatusCode])
object CompletionArg:
// conversions defining the possible arguments to pass to `complete`
// these always come with CompletionArg
// They can be invoked explicitly, e.g.
//
// CompletionArg.fromStatusCode(statusCode)
given fromString : Conversion[String, CompletionArg] = Error(_)
given fromFuture : Conversion[Future[HttpResponse], CompletionArg] = Response(_)
given fromStatusCode: Conversion[Future[StatusCode], CompletionArg] = Status(_)
end CompletionArg
import CompletionArg.*
def complete[T](arg: CompletionArg) = arg match
case Error(s) => ...
case Response(f) => ...
case Status(code) => ...
end Completions

Эта конструкция сложнее, чем простая перегрузка complete

, но все же может быть полезна, если обычная перегрузка недоступна (как в случае выше, поскольку у нас не может быть двух перегруженных методов, принимающих аргументы Future[...]
), или если обычная перегрузка привела бы к комбинаторному взрыву вариантов.


Ссылки:

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.