8.8 KiB
title, description, tags
| title | description | tags | ||
|---|---|---|---|---|
| Строковые шаблоны и вывод | Интерполяция строк, raw strings, trimIndent, println и форматированный вывод |
|
Шаблоны строк
Вместо конкатенации - подстановка значений прямо в строку:
val name = "Kotlin"
val version = 2.4
println("Привет, $name!") // Привет, Kotlin!
println("Версия: $version") // Версия: 2.4
println("Длина имени: ${name.length}") // Длина имени: 6
println("Сумма: ${2 + 3}") // Сумма: 5
Правила:
$имя- для простой переменной${выражение}- для всего остального: вызовов, свойств, арифметики- вызывается
toString()подставляемого значения nullподставляется как текстnull
val x: String? = null
println("значение: $x") // значение: null
Фигурные скобки можно ставить всегда - многие так и делают для единообразия.
Экранирование
println("цена: \$100") // цена: $100
println("перенос\nстроки")
println("табуляция\tтут")
println("кавычка \" внутри")
println("слеш \\ внутри")
println("символ \u00A9") // ©
Поддерживаются \t, \b, \n, \r, \', \", \\, \$, \uXXXX.
Raw strings
Три кавычки - никакого экранирования, переносы сохраняются как есть:
val path = """C:\Users\name\file.txt""" // слеши не экранируются
val json = """
{
"name": "Kotlin",
"stable": true
}
"""
Удобно для regex, JSON, SQL, HTML.
Шаблоны $ в raw strings работают:
val user = "admin"
val query = """SELECT * FROM users WHERE name = '$user'"""
Чтобы вставить настоящий $, используют подстановку символа:
val price = """цена: ${'$'}100""" // цена: $100
trimIndent и trimMargin
Raw string сохраняет отступы исходного кода - их убирают явно:
val text = """
Первая строка
Вторая строка
""".trimIndent()
// "Первая строка\nВторая строка" — общий отступ убран,
// пустые первая и последняя строки удалены
val bar = """
|Первая
|Вторая
""".trimMargin() // по умолчанию маркер |
trimIndent() вычисляет минимальный общий отступ непустых строк и срезает его у всех.
println и print
print("без переноса")
println("с переносом")
println() // пустая строка
println(listOf(1, 2, 3)) // [1, 2, 3]
Это функции стандартной библиотеки, доступны без импорта. Под капотом - System.out.
Форматированный вывод
Kotlin использует механизм форматирования Java:
import java.util.Locale
fun main() {
println("%05d".format(42)) // 00042
println("%-10s|".format("left")) // left |
println(String.format("%s = %d", "x", 5)) // x = 5
// вещественные числа и разряды зависят от локали — её лучше задавать явно
println("%.2f".format(Locale.US, 3.14159)) // 3.14
println("%,d".format(Locale.US, 1234567)) // 1,234,567
}
[!warning] Локаль по умолчанию
formatбез явной локали берёт системную. На русской локали получится3,14и1 234 567- с запятой и неразрывными пробелами. Если строка идёт в JSON, SQL или лог, это ломает парсинг. Для машинных форматов всегда передавайтеLocale.US(илиLocale.ROOT).
Основные спецификаторы:
| Спецификатор | Значение |
|---|---|
%d |
целое число |
%f |
вещественное |
%.Nf |
вещественное с N знаками |
%s |
строка (через toString()) |
%b |
boolean |
%x |
шестнадцатеричное |
%e |
экспоненциальная запись |
%n |
перенос строки платформы |
%% |
символ процента |
Флаги ширины: %10d - по правому краю, %-10d - по левому, %010d - с ведущими нулями.
Чтение ввода
val line = readLine() // String? — null при конце потока
val text = readln() // String — бросает исключение при EOF
val n = readln().toInt() // падает на некорректном вводе
val safe = readln().toIntOrNull() ?: 0 // безопасный разбор
readln() появился в Kotlin 1.6 и удобнее, когда ввод гарантирован.
Конкатенация
Работает, но в шаблонах почти не нужна:
println("Hello" + " " + "world") // Hello world
println("Hello" + 5 + 10) // Hello510 — слева направо
println("Hello" + (5 + 10)) // Hello15
Важно: складывать можно только когда слева строка. У Int нет plus(String), поэтому в Kotlin не скомпилируется то, что в Java работает:
// println(5 + 10 + "Hello") // ошибка: Int.plus ожидает Int, а не String
println("${5 + 10}Hello") // 15Hello — через шаблон
Для сборки строки в цикле - StringBuilder или buildString:
val result = buildString {
repeat(3) { append("ха") }
}
println(result) // хахаха
Подробнее: Строки
[!info] Отличия от Java
Java Kotlin System.out.println(x)println(x)"a" + x + "b""a${x}b"String.format("%d", n)"%d".format(n)text blocks """(Java 15+)raw strings """+ шаблоны.stripIndent().trimIndent()new Scanner(System.in)readln()Шаблоны - не просто синтаксический сахар: компилятор собирает их через
StringBuilderилиinvokedynamic, то есть без промежуточных строк. Писать"a" + b + "c"ради производительности не нужно.Сравнить: Форматированный вывод в Java
[!warning] Подводные камни
$перед словом всегда считается шаблоном. Строка"цена: $100"скомпилируется (цифра не может начинать имя), а"$name_suffix"- нет: Kotlin ищет переменнуюname_suffix. Нужны скобки:"${name}_suffix".
trimIndent()чувствителен к смешению табов и пробелов - отступ считается по символам, таб и четыре пробела для него разные вещи.
$в regex внутри raw string."""^\d+$"""работает, потому что после$идёт конец строки. Но"""$\d"""компилятор попытается разобрать как шаблон.Шаблон вызывает
toString()у массива, а не его содержимое:val arr = arrayOf(1, 2, 3) println("$arr") // [Ljava.lang.Object;@1b6d3586 println(arr.contentToString()) // [1, 2, 3] println("${arr.joinToString()}") // 1, 2, 3
readLine()возвращаетString?. ВызовreadLine().toInt()не скомпилируется - нуженreadln()или обработка null.
Дополнительно: Строки Далее: Пакеты и импорты