Kotlin тип безопасных типов - PullRequest
0 голосов
/ 25 апреля 2018

Я часто использую typealiases в своем коде Kotlin, но мне интересно, смогу ли я обеспечить безопасность типов для них.

typealias Latitude = Double
typealias Longitude = Double

fun someFun(lat: Latitude, lon: Longitude) {...}

val lat: Latitude = 12.34
val lon: Longitude = 56.78
someFun(lon, lat) // parameters are in a wrong order, but the code compiles fine

Было бы хорошо, если бы я мог как-то предотвратить неявное приведение между typealiases, помогаячтобы избежать таких проблем.

Конечно, существует проблема, заключающаяся в том, что операции над базовыми типами будут недоступны для typealiases, но это может быть решено с помощью функций расширения (или приведения).

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

Итак, вопрос: могу ли я каким-то образом обеспечить безопасность типов для typealiases?

Ответы [ 3 ]

0 голосов
/ 25 апреля 2018

К сожалению, вы не можете избежать этого в настоящее время. Выполняется функция - встроенные классы (# 9 в этом документе) , которая решит проблему с накладными расходами во время выполнения, обеспечивая при этом безопасность типов во время компиляции. Это выглядит очень похоже на классы значений Scala , которые удобны, если у вас много данных, и обычные классы case будут непроизводительными.

0 голосов
/ 25 апреля 2018

Определяя Latitude, а также Longitude как псевдонимы для Double, его можно рассматривать как транзитивные псевдонимы, т. Е. Вы определили Latitude как псевдоним для Longitude и наоборот.Теперь все три типа имен могут использоваться взаимозаменяемо:

val d: Double = 5.0
val x: Latitude = d
val y: Longitude = x

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

fun someFun(latitude: Double, longitude: Double) {
}

fun main(args: Array<String>) {
    val lat = 12.34
    val lon = 56.78
    someFun(latitude = lon, longitude = lat)
}
0 голосов
/ 25 апреля 2018

К сожалению, это невозможно с typealiases. Ссылка на котлин гласит:

Псевдонимы типов не вводят новые типы. Они эквивалентны соответствующие базовые типы. Когда вы добавляете typealias Predicate<T> и используйте Predicate<Int> в своем коде, компилятор Kotlin всегда расширяется это к (Int) -> Boolean. Таким образом, вы можете передать переменную вашего типа всякий раз, когда требуется общий тип функции и наоборот:

typealias Predicate<T> = (T) -> Boolean

fun foo(p: Predicate<Int>) = p(42)

fun main(args: Array<String>) {
    val f: (Int) -> Boolean = { it > 0 }
    println(foo(f)) // prints "true"

    val p: Predicate<Int> = { it > 0 }
    println(listOf(1, -2).filter(p)) // prints "[1]"
}

См. Псевдонимы типа kotlin .

tl; dr Вы должны использовать (данные) классы

Как следует из названия typealias, typealias - это только псевдоним, а не новый тип. В вашем примере Latitude и Longitude являются Ints, независимо от их имен. Чтобы сделать их безопасными, вы должны объявить тип. Теоретически вы можете наследовать новые типы от Int. Поскольку Int является последним классом, это невозможно. Поэтому его необходимо создать новый класс.

...