На этом шаге мы рассмотрим назначение и применение этой функции.
Следующая стандартная функция в списке - это run. Функция run похожа на apply, точно так же ограничивая относительную область видимости, но не возвращает объект-приемник.
Например, вот как можно проверить наличие конкретной строки в файле:
val menuFile = File("menu-file.txt") val servesDragonsBreath = menuFile.run { readText().contains("Dragon's Breath") }
Функция readText() неявно вызывается относительно объекта-приемника - экземпляра File - подобно функциям setReadable(), setWritable() и setExecutable() в примере с apply. Но в отличие от apply, run возвращает результат лямбды - в нашем случае истину или ложь.
Функция run может также использоваться для выполнения ссылки на функцию относительно объекта-приемника. Мы уже использовали ссылки на функции (смотри 57 шаг): вот пример, как сделать это с run:
fun nameIsLong(name: String) = name.length >= 20 "Madrigal".run(::nameIsLong) // Ложь "Polarcubis, Supreme Master of NyetHack".run(::nameIsLong) // Истина
Конечно, вторую строку в этом примере можно заменить прямым вызовом nameIsLong("Madrigal"), однако выгоды от использования run становятся более очевидными, когда требуется вызвать несколько функций: вызов цепочкой с помощью run проще читать и анализировать. Например, взгляните на следующий код, который проверяет длину имени игрока, формирует сообщение в зависимости от результата и выводит его.
fun nameIsLong(name: String) = name.length >= 20 fun playerCreateMessage(nameTooLong: Boolean): String { return if (nameTooLong) { "Name is too long. Please choose another name." } else { "Welcome, adventurer" } } "Polarcubis, Supreme Master of NyetHack" .run(::nameIsLong) .run(::playerCreateMessage) .run(::println)
Сравните цепочку вызовов в run с тремя вложенными вызовами функций:
println(playerCreateMessage(nameIsLong("Polarcubis, Supreme Master of NyetHack")))
Вложенные вызовы функций сложнее понять, потому что читатель должен читать код справа налево, а не слева направо, как мы привыкли.
Обратите внимание, что есть другая форма вызова run, без объекта-приемника. Эта форма встречается гораздо реже, но мы включим ее сюда для полноты описания:
val status = run { if (healthPoints == 100) "perfect health" else "has injuries" }
На следующем шаге мы рассмотрим функцию with.