остатки
Свойства и функции перечислений
В предыдущем примере мы добавили свойство в BandMember, включив его в кон-
структор класса перечисления. Свойства и функции также могут добавляться в
основное тело класса. Например, следующий код добавляет функцию sings в класс
перечисления BandMember:
enum class BandMember(val instrument: String) {
JERRY("lead guitar"),
BOBBY("rhythm guitar"),
PHIL("bass"); Обратите внимание: функция sings() должна отделяться
от значений перечисления символом «;».
fun sings() = "occasionally" веУотзквсаряжафдщоуагноектцзнисаятчсерниоимкяуепн«еерoмcеcчsaиinsсigлosеn(н)a,иllякyо»ит.моер-ая
}
Каждое значение, определенное в классе перечисления, может определять свойства
и функции, унаследованные от определения класса. В следующем примере функция
sings определяется для JERRY и BOBBY:
enum class BandMember(val instrument: String) {
JERRY("lead guitar") {
override fun sings() = "plaintively"
}, JстERвRенYниуюBOреBаBлYизиамциеюютsinсgоsб(-).
BOBBY("rhythm guitar") {
override fun sings() = "hoarsely"
},
PHIL("bass");
open fun sings() = "occasionally" Так как мы переопределяем функцию
} sings() для двух значений, ее необходи-
мо пометить префиксом open.
После этого вы сможете вызвать функцию sings для выбранного участника группы:
fun main(args: Array<String>) { Эта строка вызывает функцию
var selectedBandMember: BandMember sings() участника JERRY и выдает
selectedBandMember = BandMember.JERRY результат «plaintively».
println(selectedBandMember.instrument)
println(selectedBandMember.sings())
}
дальше 4 451
изолировать или не ограничивать
4. Изолированные классы
Как упоминалось ранее, классы перечислений позволяют создать ограниченный набор фик-
сированных значений, но в некоторых ситуациях желательно иметь чуть больше гибкости.
Предположим, вы хотите использовать в приложении два разных типа сообщений: для
успеха и для неудачи. Все сообщения должны ограничиваться этими двумя типами.
Если вы захотите смоделировать эту конфигурацию с классами перечислений, код может
выглядеть так:
enum class MessageType(var msg: String) {
SUCCESS("Yay!"), Класс перечисления MessageType содер-
FAILURE("Boo!") жит два значения: SUCCESS и FAILURE.
}
Тем не менее у такого решения есть пара недостатков:
Каждое значение — константа, которая существует в единственном экземпляре.
Скажем, вы не сможете изменить свойство msg значения SUCCESS в одной конкретной
ситуации, так как это изменение отразится во всем коде вашего приложения.
Каждое значение должно содержать одинаковый набор свойств и функций.
Например, в значение FAILURE будет удобно добавить свойство Exception, чтобы
вы могли проанализировать, что именно пошло не так, но класс перечисления не даст
такой возможности.
Что же делать?
На помощь приходят изолированные классы!
Для решения подобных проблем используются изолированные классы. Изолированный (sealed) класс
напоминает расширенную версию класса перечисления. Он позволяет ограничить иерархию классов
конкретным множеством подтипов, каждый из которых может определять собственные свойства и
функции. Кроме того, в отличие от класса перечисления, вы можете создать несколько экземпляров
каждого типа.
Чтобы создать изолированный класс, поставьте перед именем класса префикс sealed. Например,
следующий фрагмент создает изолированный класс с именем MessageType, с двумя подтипами —
MessageSuccess и MessageFailure. У каждого подтипа имеется строковое свойство msg, а подтип
MessageFailure содержит дополнительное свойство Exception с именем e:
sealed class MessageType КлялеатсссяMиeзsоsлagиeрTоyвpанeняывм- . синMт аоeсвпsлаsреaевдgд уeсеюSвлоuтяиcюсхcятeкsоsостниосбтMMстрeesуsвssкеaaтнggнeeоыFTрaеyаiplхсue.вrоeй-
class MessageSuccess(var msg: String) : MessageType()
class MessageFailure(var msg: String, var e: Exception) : MessageType()
452 приложение
остатки
Как использовать изолированные классы
Как мы уже говорили, изолированный класс позволяет создать несколько экземпляров
каждого подтипа. Например, следующий код создает два экземпляра MessageSuccess
и один экземпляр MessageFailure:
fun main(args: Array<String>) {
val messageSuccess = MessageSuccess("Yay!")
val messageSuccess2 = MessageSuccess("It worked!")
val messageFailure = MessageFailure("Boo!", Exception("Gone wrong."))
}
После этого вы можете создать переменную MessageType
и присвоить ей одно из сообщений:
fun main(args: Array<String>) {
val messageSuccess = MessageSuccess("Yay!")
val messageSuccess2 = MessageSuccess("It worked!")
val messageFailure = MessageFailure("Boo!", Exception("Gone wrong."))
var myMessageType: MessageType = messageFailure пткmлроeаимsссsсвуaооgмеиeгтFоMaьiэelкumsзsraеeyмgMяeпвeTллsysяяpaерegт,eмTспояyожpэп-нeо.од-
}
А поскольку MessageType является изолированным классом с ограни-
ченным набором подтипов, для проверки всех подтипов можно вос-
пользоваться конструкцией when без дополнительной секции else:
fun main(args: Array<String>) {
val messageSuccess = MessageSuccess("Yay!")
val messageSuccess2 = MessageSuccess("It worked!")
val messageFailure = MessageFailure("Boo!", Exception("Gone wrong."))
var myMessageType: MessageType = messageFailure сmMтяyeетsMлsьaоeнgлsоseьaйFкgaосeiеlTкuкyrцтpeиe,ииппмeоуоlэsжтMe еeнотsемsтaуоgтвeн Sендоuообcспхcиооeтлдssниьими--лоисти.
val myMessage = when (myMessageType) {
is MessageSuccess -> myMessageType.msg
is MessageFailure -> myMessageType.msg + " " + myMessageType.e.message
}
println(myMessage)
}
За дополнительной информацией о создании и использовании изо-
лированных классов обращайтесь по адресу https://kotlinlang.org/docs/
reference/sealed-classes.html
дальше 4 453
вложенные и внутренние классы
5. Вложенные и внутренние классы Вложенные классы
в Kotlin похожи
Вложенный класс определяется внутри другого класса. Это может быть на статические
полезно, если вы хотите наделить внешний класс расширенной функцио- вложенные классы
нальностью, выходящей за пределы его основного предназначения, или в языке Java.
определить код ближе к месту его использования.
Чтобы определить вложенный класс, заключите его в фигурные скобки
внутри внешнего класса. Например, следующий код определяет класс с име-
нем Outer, внутри которого находится вложенный класс с именем Nested:
class Outer {
val x = "This is in the Outer class"
class Nested { Вложенный класс размеща-
val y = "This is in the Nested class" ется полностью внутри
fun myFun() = "This is the Nested function" внешнего класса.
}
}
После этого вы можете обращаться к классу Nested и его
свойствам и функциям следующим образом:
fun main(args: Array<String>) {
val nested = Outer.Nested() Создает экземпляр Nested
println(nested.y) и присваивает его переменной.
println(nested.myFun())
}
Учтите, что вы не сможете обратиться к вложенному классу из экземпляра внеш-
него класса без предварительного создания свойства этого типа внутри внешнего
класса. Например, следующий код компилироваться не будет:
val nested = Outer().Nested() Не компилируется, так как мы
используем Outer(), а не Outer.
Другое ограничение заключается в том, что экземпляр внешнего класса недосту-
пен для вложенного класса, поэтому вложенный класс не сможет обращаться к его
компонентам. Например, вы не сможете обратиться к свойству x класса Outer из
класса Nested, поэтому следующая строка не компилируется:
class Outer {
val x = "This is in the Outer class"
class Nested { Вложенный класс не видит x,
fun getX() = "Value of x is: $x" так как переменная определя-
ется в классе Outer, поэтому
} эта строка не компилируется.
}
454 приложение
остатки
Внутренний класс может обращаться к компонентам внешнего класса
Если вы хотите, чтобы вложенный класс мог обращаться к свойствам и функциям,
определенным его внешним классом, преобразуйте его во внутренний класс. Для
этого вложенный класс помечается префиксом inner. Пример:
class Outer { ВлТккккяоа нлкетскуатовитсмоомсрйрспIсыоеоnотнбйбнnонревeймиануrйзтовмxожлкамооклемжж,лтаасвеевсснтноэснебптаыршороOайбенмщрдuексагtалтптeотаrрсаки.иьсвлтсм,-аяьессрсяае.
val x = "This is in the Outer class"
inner class Inner {
val y = "This is in the Inner class"
fun myFun() = "This is the Inner function"
fun getX() = "The value of x is: $x"
}
}
Чтобы обратиться к внутреннему классу, создайте экземпляр внешнего класса, а за-
тем на его основе создайте экземпляр внутреннего класса. В следующем примере
используются классы Outer и Inner, определенные выше:
fun main(args: Array<String>) { Inner — внутренний класс, поэтому необходимо
val inner = Outer().Inner() использовать Outer(), а не Outer.
println(inner.y)
println(inner.myFun())
println(inner.getX())
}
Также можно обратиться к внутреннему классу, создав экземпляр
свойства этого типа во внешнем классе, как в следующем примере:
class Outer { Свойство myInner класса
val myInner = Inner() Outer содержит ссылку на
экземпляр его класса Inner.
inner class Inner {
... x: String
} y: String
} Outer
fun main(args: Array<String>) { Inner
Объекты Inner и Outer имеют
val inner = Outer().myInner особую связь. Inner может ис-
пользовать переменные Outer,
} и наоборот.
Ключевой момент заключается в том, что экземпляр внутреннего
класса всегда связывается с конкретным экземпляром внешнего класса,
поэтому вы не сможете создать объект Inner без предварительного
создания объекта Outer.
дальше 4 455
объекты
6. Объявления объектов и выражения
В некоторых случаях нужна гарантия, что может быть создан толь- Емопебксаиълттиеп»ктрвтоы(ее«ракзСнтняаиванилк«гряоОлеомттвдыаиоснннясио»яачп),ннавыоатблйKътоoоягtеобвlрълмinне-.наи-е
ко один экземпляр заданного типа, например, когда один объект
должен координировать некие действия в масштабах приложения.
В таких ситуациях можно воспользоваться ключевым словом
object для создания объявления объекта.
Объявление объекта определяет объявление класса и создает его
экземпляр в одной команде. А когда оно включается на верхнем
уровне исходного файла или пакета, может быть создан только
один экземпляр этого типа.
Объявление объекта выглядит примерно так:
package com.hfkotlin.mypackage Объявление объ-
екта определяет
DuckManager — объект. класс и создает
object DuckManager { его экземпляр
в одной команде.
val allDucks = mutableListOf<Duck>()
fun herdDucks() { Содержит свойство с именем allDucks
и функцию с именем herdDucks().
//Код для работы с объектами Duck
}
}
Как видите, объявление объекта похоже на определение класса,
если не считать того, что перед ним ставится префикс object, а не
class. Как и класс, объект может обладать свойствами, функци-
ями и блоками инициализации, может наследоваться от классов
и интерфейсов. Впрочем, в объявление объекта нельзя добавить
конструктор. Дело в том, что объект автоматически создается
сразу же после обращения, поэтому конструктор будет лишним.
К объекту, созданному с использованием объявления объекта, вы
обращаетесь по имени; через него также можно обращаться к ком-
понентам объекта. Например, если вы хотите вызвать функцию
herdDucks объекта DuckManager, это можно сделать так:
DuckManager.herdDucks()
Наряду с добавлением объявления объекта на верхнем уровне ис-
ходного файла или пакета, вы также можете добавить его в класс.
Давайте посмотрим, как это делается.
456 приложение
остатки
Объекты классов...
В следующем коде объявление объекта DuckFactory добавляется
в класс с именем Duck:
class Duck { Оетбъсяяввлеонсинеовонбоъмекттеалеракзлмаесщсаа. - Добавьте объявле-
object DuckFactory { ние объекта в класс,
чтобы создать оди-
fun create(): Duck = Duck() ночный экземпляр
этого типа, принад-
} лежащий классу.
}
При добавлении объявления объекта в класс создается объект, принад-
лежащий этому классу. Для класса создается один экземпляр объекта,
совместно используемый всеми экземплярами этого класса.
Добавив объявление объекта, вы можете обращаться к объекту из класса
с использованием точечной записи. Например, следующий код вызывает
функцию create объекта DuckFactory и присваивает результат новой
переменной с именем newDuck:
val newDuck = Duck.DuckFactory.create() Обратите внимание: для обра-
щения к объекту используется
...и объекты-компаньоны запись Duck, а не Duck().
Один объект для класса может быть помечен как объект-компаньон при помощи префикса
companion. Объект-компаньон похож на объект класса, не считая того, что его имя можно
не указывать. Например, следующий код превращает объект DuckFactory из приведенного
выше примера в безымянный объект-компаньон:
class Duck { Еплуаскрлнаеиизфыиипвкоиассмттcяьoамmвииомpтжaянnьооiбoпъnуеке,ркаевтздаамаот.буьъВж.япверлонечнее ипмерм,ипдоребитъежскяет-а
companion object DuckFactory {
fun create(): Duck = Duck()
}
}
Если вы создали объект-компаньон, для обращения к нему Объект-компаньон мо-
достаточно указать имя класса. Например, следующий код жет использоваться как
вызывает функцию create(), определенную объектом-ком-
паньоном Duck: Kotlin-аналог статических
val newDuck = Duck.create() методов в языке Java.
Для получения ссылки на безымянный объект-компаньон
Любые функции, добавлен-
используется ключевое слово Companion. Например, следу- ные в объект-компаньон,
ющий код создает новую переменную с именем x и присваи-
вает ей ссылку на объект-компаньон класса Duck:
val x = Duck.Companion совместно используются
всеми экземплярами класса.
После знакомства с объявлениями объектов и объекта-
ми-компаньонами обратимся к объектным выражениям.
дальше 4 457
объектные выражения
Объектные выражения
Объектным выражением называется выражение, которое «на ходу» создает анонимный
объект без заранее определенного типа.
Допустим, вы хотите создать объект для хранения исходного значения координат x и y.
Чтобы не определять класс Coordinate и не создавать экземпляр этого класса, вы можете
создать объект, использующий свойства для хранения значений координат x и y. Например,
следующий код создает новую переменную с именем startingPoint и присваивает ей
такой объект:
val startingPoint = object {
val x = 0 Создает объект с двумя
val y = 0 свойствами, x и y.
}
После этого для обращения к компонентам объекта можно использовать следующую запись:
println("starting point is ${startingPoint.x}, ${startingPoint.y}")
Объектные выражения обычно используются как аналоги анонимных внутренних классов
языка Java. Если вы пишете некий GUI-код и вдруг понимаете, что вам нужен экземпляр
класса, реализующий абстрактный класс MouseAdapter, используйте объектные выраже-
ния для создания экземпляра на ходу. Например, следующий код передает объект функции
с именем addMouseListener; объект реализует интерфейс MouseAdapter и переопределяет
его функции mouseClicked и mouseEntered:
Эта команда... Объектное выраже-
window.addMouseListener(object : MouseAdapter() { ние, выделенное жирным
override fun mouseClicked(e: MouseEvent) { шрифтом, фактиче-
//Код, выполняемый при щелчке кнопкой мыши ски означает «создать
} экземпляр класса (без
имени), который реа-
...закан- override fun mouseReleased(e: MouseEvent) { лизует MouseAdapter —
чивается //Код, выполняемый при отпускании кнопки мыши а вот его реализации
здесь. функций mouseClicked
} и mouseReleased». Дру-
}) гими словами, мы
предоставляем функции
Дополнительную информацию об объявлениях объектов addMouseListener реали-
и выражениях см. здесь: зацию класса и экзем-
пляр этого класса имен-
https://kotlinlang.org/docs/reference/object-declarations.html но там, где он нужен.
458 приложение
остатки
7. Расширения
Расширения позволяют добавлять новые функции и свойства в суще- Также существуют
ствующий тип без создания нового подтипа. библиотеки расширения
Kotlin, которые могут ис-
Представьте, что вы пишете приложение, в котором часто приходится пользоваться для упроще-
снабжать значение Double префиксом $, чтобы отформатировать его в ния программирования, —
виде денежной суммы. Чтобы не повторять одно и то же действие снова такие, как Anko и Android
и снова, можно написать функцию расширения с именем toDollar, KTX для разработки при-
которая может использоваться с Double. Эта задача решается так: ложений Android.
Определяет функцию с именем toDollar(),
fun Double.toDollar(): String { которая расширяет Double.
return "$$this" Вернуть текущее значение
} с префиксом $.
Приведенный выше код указывает, что функция с именем Паттерны
toDollar, которая возвращает строку, может использоваться со проектирования
значениями Double. Функция получает текущий объект (обознача-
емый this), ставит перед ним префикс $ и возвращает результат. Паттерны проектиро-
вания представляют
Созданная функция расширения используется так же, как любая собой универсальные
другая функция. Например, в следующем фрагменте функция решения типичных
toDollar вызывается для переменной Double со значением 45.25: задач. Kotlin предостав-
ляет простые и удобные
var dbl = 45.25 //Выводит $45.25 средства для реализации неко-
println(dbl.toDollar()) торых из этих паттернов.
Объявления объектов
Расширения свойств создаются так же, как расширения функций. предоставляют возможность
В следующем коде создается свойство расширения для String реализации паттерна «Одиноч-
с именем halfLength, которое возвращает длину текущей строки, ный объект», так как каждое
разделенную на 2.0: объявление создает одиночный
экземпляр этого объекта. Рас-
val String.halfLength Определяет свойство ширения могут использоваться
get() = length / 2.0 halfLength, которое может вместо паттерна «Декоратор»,
использоваться со строками. поскольку они позволяют рас-
ширять поведение классов и
Пример кода, в котором используется новое свойство: объектов. А если вас интересует
паттерн «Делегирование» как
val test = "This is a test" альтернатива наследованию,
обращайтесь за дополнитель-
println(test.halfLength) //Выводит 7.0 ной информацией по адресу
https://kotlinlang.org/docs/
Дополнительная информация об использовании расширений, reference/delegation.html
в том числе и о добавлении их в объекты-компаньоны, доступна
по адресу https://kotlinlang.org/docs/reference/extensions.html
Об использовании this можно подробнее узнать здесь:
https://kotlinlang.org/docs/reference/this-expressions.html
дальше 4 459
передача управления
8. Return, break и continue
В Kotlin предусмотрены три способа выхода из цикла:
return
Как вы уже знаете, эта команда осуществляет возврат из включающей функции.
break
Команда завершает вмещающий цикл (осуществляет переход к точке после
его завершения), например:
var x = 0
var y = 0
while (x < 10) {
x++ Эзкаати звнеyоарт+чш+е.канxоеидтие муyцвеиеоелксттилчиабитеевзтаоевсгтыоявпроxоае,лвнпзненоынасмилчяеен0счи.теегро1о,-
break
y++
}
continue
Команда переходит к следующей итерации цикла, например:
var x = 0
var y = 0
while (x < 10) {
x++ wУвhеiлleич(xив<ае1т0)xб,епз овсылпе очленгеонвиоязвсртарщоакеитyс+я+.кПсетрер-оке
continue
y++ мн(xиеен<нx1ар0яа)xвннпеорсо1тд0оа,лнажетазнеатрчаевуннвиыеелмиyчfоиaсвlsтаeт.аИеьтстяс,оягпороваковаенуызснмлаоч0веи.-е
}
Использование меток с break и continue
Если вы используете вложенные циклы, можно явно указать, из какого цикла вы хотите вый-
ти, — для этого следует указать метку. Метка состоит из имени, за которым следует символ @.
Например, в следующем коде представлены два цикла, один из которых вложен в другой.
Внешний цикл имеет метку с именем myloop@, которая используется в выражении break:
myloop@ while (x < 20) {
while (y < 20) {
x++
break@myloop Означает «выйти из цикла с мет-
} кой myloop@ (внешнего цикла)».
}
При использовании break с меткой команда осуществляет переход к концу вмещающего цик-
ла с указанной меткой, так что в приведенном примере будет завершен внешний цикл. При
использовании continue с меткой происходит переход к следующей итерации этого цикла.
460 приложение
остатки
Использование меток с return
При помощи меток также можно управлять поведением кода во вложенных
функциях, включая функции высшего порядка.
Предположим, имеется следующая функция, которая включает вызов forEach —
встроенной функции высшего порядка, получающей лямбда-выражение:
fun myFun() {
listOf("A", "B", "C", "D").forEach {
if (it == "C") return лпЗярдмеосибьсдхаrо-eдвtиuытrрnавжиысехпноиодля.ьизПзурфеитуднсокясцтвинииужтmерyниFиuиnr()e.turn
println(it)
}
println("Finished myFun()")
}
В этом примере программа выходит из функции myFun при достижении выра-
жения return, поэтому строка
println("Finished myFun()")
никогда не выполняется.
Если вы хотите выйти из лямбда-выражения, но при этом продолжить выполне-
ние myFun, добавьте метку в лямбда-выражение и укажите ее в return. Пример:
fun myFun() {
listOf("A", "B", "C", "D").forEach myloop@{
if (it == "C") return@myloop Лямбда-выражение, которое передается функции
println(it) forEach, снабжено меткой myloop@. В выраже-
} нии return лямбда-выражения используется эта
println("Finished myFun()") метка, поэтому при его достижении происхо-
} дит выход из лямбда-выражения, а управление
передается на сторону вызова (цикл forEach).
Это можно заменить неявной меткой, имя которой соответ-
ствует функции, которой было передано лямбда-выражение:
fun myFun() {
listOf("A", "B", "C", "D").forEach {
if (it == "C") return@forEach Здесь при помощи неявной мет-
println(it) ки мы говорим программе выйти
} из лямбда-выражения и вернуться
println("Finished myFun()") на сторону его вызова (цикл forEach).
}
За дополнительной информацией об использовании меток
для передачи управления в программе обращайтесь по адресу
https://kotlinlang.org/docs/reference/returns.html
дальше 4 461
дополнительные возможности функций
9. Дополнительные возможности функций
О функциях в этой книге было сказано достаточно много, но у них есть еще
несколько возможностей, о которых, как нам кажется, вам стоило бы знать.
vararg Только один пара-
метр может быть
Если вы хотите, чтобы функция получала несколько аргументов одного помечен ключевым
типа, но точное количество этих аргументов неизвестно, поставьте словом vararg.
перед этим параметром префикс vararg. Он сообщает компилятору, Этот параметр
что параметр может получать переменное количество аргументов. обычно стоит на
Пример: последнем месте.
Префикс vararg означает, что в параметре
ints могут передаваться несколько значений.
fun <T> valuesToList(vararg vals: T): MutableList<T> {
val list: MutableList<T> = mutableListOf()
for (i in vals) {
list.add(i) Значения vararg передаются функции
в виде массива, так что мы можем
} перебрать все значения. В следующем
return list
} фрагменте каждое значение добавля-
ется в MutableList.
При вызове функции с передачей vararg ей передаются значения —
точно так же, как при вызове любых других функций. Например,
в следующем примере функции valuesToList передаются пять зна-
чений Int:
val mList = valuesToList(1, 2, 3, 4, 5)
Если у вас имеется готовый массив значений, вы можете передать их
функции, поставив перед именем массива префикс * — так называе-
мый оператор распространения. Пара примеров его использования:
val myArray = arrayOf(1, 2, 3, 4, 5) Значения, содержащиеся в myArray,
val mList = valuesToList(*myArray) передаются функции valuesToList.
val mList2 = valuesToList(0, *myArray, 6, 7)
Функции передается 0... ...за ним ...и наконец, 6 и 7.
следует
содержимое
myArray...
462 приложение
остатки
infix
Если поставить перед функцией префикс infix, ее можно будет вызывать без ис-
пользования точечной записи. Пример функции с префиксом infix:
Помеча- class Dog { bark(x: Int): String {
infix fun
ем функ-
цию bark() //Код, выполняющий операцию bark для Dog x раз
префиксом
infix. }
}
Так как функция была помечена ключевым словом infix, ее вызов может выглядеть
так:
Dog() bark 6 Создает экземпляр Dog и вызывает его функ-
цию bark(), передавая функции значение 6.
Функция может быть помечена ключевым словом infix, если она является функцией
класса или функцией расширения, имеет один параметр без значения по умолчанию
и не имеет пометки vararg.
inline
Функции высшего порядка иногда работают медленнее обычных, но достаточно
часто их быстродействие можно повысить, поставив перед ними префикс inline,
как в следующем примере:
inline fun convert(x: Double, converter: (Double) -> Double) : Double {
val result = converter(x) обПныеалраепдосмовзаедмчаеиннаафвуп нгрлкеацфвииеяк,1ско1ом,тнiооnрlзiаnдяeе.сь
println("$x is converted to $result")
return result
}
Когда функция объявляется подобным образом, в сгенерированном коде вызов
функции заменяется ее непосредственным содержимым. При этом устраняются до-
полнительные затраты на вызов функции, что часто ускоряет выполнение функции,
но во внутренней реализации при этом генерируется больший объем кода.
За дополнительной информацией об этих (и многих других)
возможностях обращайтесь по адресу https://kotlinlang.org/
docs/reference/functions.html
дальше 4 463
совместимость
10. Совместимость
Как было сказано в начале книги, код Kotlin совместим с Java и может
транспилироваться в JavaScript. Если вы собираетесь использовать свой
код Kotlin с другими языками, рекомендуем ознакомиться в электронной
документации Kotlin с разделами, посвященными совместимости.
Совместимость с Java
Практически любой код Java может вызваться в Kotlin без малейших
проблем. Просто импортируйте любые библиотеки, которые не были
импортированы автоматически, и используйте их. Обо всех дополнитель-
ных факторах — а также о том, как Kotlin работает со значениями null,
получаемыми из Java, — можно прочитать здесь:
https://kotlinlang.org/docs/reference/java-interop.html
Использование кода Kotlin из Java рассматривается здесь:
https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html
Использование Kotlin с JavaScript
Электронная документация также включает разнообразную информацию
об использовании Kotlin с JavaScript. Например, если ваше приложение
ориентировано на JavaScript, вы можете воспользоваться типом Kotlin
dynamic, который фактически отключает проверку типов Kotlin:
val myDynamicVariable: dynamic = ...
О типе dynamic более подробно рассказано здесь: Еввсцоарслезптеявмилилфк ещньKсоаовhвоrфжытмoаыtпсeрttйовнfхоемфlpхeтороiндnrоsпйемосдд:eте.нт/лреуnсакнЗ/рамеиьcцоьыkатмжeтдиеoпх/инкедфtнеооmсйноопlазiпопйыnиранuороомхднlоаlмaлмtлремекеnьiпнснкеpаотзнgркисотхмlоо.aоуотг,oь-гtиалоеrмоfет-кхьgoплткы/rоьльиdmб-онахoрвто.chайst--/ml
https://kotlinlang.org/docs/reference/dynamic-type.html
Следующая страница содержит информацию об использовании
JavaScript из Kotlin:
https://kotlinlang.org/docs/reference/js-interop.html
Наконец, информацию об обращении к коду Kotlin из JavaScript
смотрите здесь:
https://kotlinlang.org/docs/reference/js-to-kotlin-interop.html
Написание платформенного кода на Kotlin
Режим Kotlin/Native позволяет компилировать код Kotlin в плат-
форменные двоичные файлы. Если вам захочется больше узнать
об этой возможности, обращайтесь по следующему адресу:
https://kotlinlang.org/docs/reference/native-overview.html
464 приложение