Added kotlin guide. (WIP) (15.10.26)

This commit is contained in:
2026-10-15 00:24:21 +03:00
parent dc82207723
commit da3ad9dd1a
13 changed files with 2120 additions and 0 deletions
@@ -0,0 +1,191 @@
---
title: Строковые шаблоны и вывод
description: Интерполяция строк, raw strings, trimIndent, println и форматированный вывод
tags:
- kotlin
- syntax
---
## Шаблоны строк
Вместо конкатенации - подстановка значений прямо в строку:
```kotlin
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`
```kotlin
val x: String? = null
println("значение: $x") // значение: null
```
Фигурные скобки можно ставить всегда - многие так и делают для единообразия.
## Экранирование
```kotlin
println("цена: \$100") // цена: $100
println("перенос\nстроки")
println("табуляция\tтут")
println("кавычка \" внутри")
println("слеш \\ внутри")
println("символ \u00A9") // ©
```
Поддерживаются `\t`, `\b`, `\n`, `\r`, `\'`, `\"`, `\\`, `\$`, `\uXXXX`.
## Raw strings
Три кавычки - никакого экранирования, переносы сохраняются как есть:
```kotlin
val path = """C:\Users\name\file.txt""" // слеши не экранируются
val json = """
{
"name": "Kotlin",
"stable": true
}
"""
```
Удобно для regex, JSON, SQL, HTML.
Шаблоны `$` в raw strings **работают**:
```kotlin
val user = "admin"
val query = """SELECT * FROM users WHERE name = '$user'"""
```
Чтобы вставить настоящий `$`, используют подстановку символа:
```kotlin
val price = """цена: ${'$'}100""" // цена: $100
```
## trimIndent и trimMargin
Raw string сохраняет отступы исходного кода - их убирают явно:
```kotlin
val text = """
Первая строка
Вторая строка
""".trimIndent()
// "Первая строка\nВторая строка" — общий отступ убран,
// пустые первая и последняя строки удалены
val bar = """
|Первая
|Вторая
""".trimMargin() // по умолчанию маркер |
```
`trimIndent()` вычисляет минимальный общий отступ непустых строк и срезает его у всех.
## println и print
```kotlin
print("без переноса")
println("с переносом")
println() // пустая строка
println(listOf(1, 2, 3)) // [1, 2, 3]
```
Это функции стандартной библиотеки, доступны без импорта. Под капотом - `System.out`.
## Форматированный вывод
Kotlin использует механизм форматирования Java:
```kotlin
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` - с ведущими нулями.
## Чтение ввода
```kotlin
val line = readLine() // String? — null при конце потока
val text = readln() // String — бросает исключение при EOF
val n = readln().toInt() // падает на некорректном вводе
val safe = readln().toIntOrNull() ?: 0 // безопасный разбор
```
`readln()` появился в Kotlin 1.6 и удобнее, когда ввод гарантирован.
## Конкатенация
Работает, но в шаблонах почти не нужна:
```kotlin
println("Hello" + " " + "world") // Hello world
println("Hello" + 5 + 10) // Hello510 — слева направо
println("Hello" + (5 + 10)) // Hello15
```
Важно: складывать можно только когда **слева** строка. У `Int` нет `plus(String)`, поэтому в Kotlin не скомпилируется то, что в Java работает:
```kotlin
// println(5 + 10 + "Hello") // ошибка: Int.plus ожидает Int, а не String
println("${5 + 10}Hello") // 15Hello — через шаблон
```
Для сборки строки в цикле - `StringBuilder` или `buildString`:
```kotlin
val result = buildString {
repeat(3) { append("ха") }
}
println(result) // хахаха
```
Подробнее: [Строки](../Работа%20с%20данными/Строки.md)
> [!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](../../../Программирование%20на%20Java/Синтаксис%20и%20типы/Базовый%20синтаксис/Форматированный%20вывод.md)
> [!warning] Подводные камни
> **`$` перед словом всегда считается шаблоном.** Строка `"цена: $100"` скомпилируется (цифра не может начинать имя), а `"$name_suffix"` - нет: Kotlin ищет переменную `name_suffix`. Нужны скобки: `"${name}_suffix"`.
>
> **`trimIndent()` чувствителен к смешению табов и пробелов** - отступ считается по символам, таб и четыре пробела для него разные вещи.
>
> **`$` в regex внутри raw string.** `"""^\d+$"""` работает, потому что после `$` идёт конец строки. Но `"""$\d"""` компилятор попытается разобрать как шаблон.
>
> **Шаблон вызывает `toString()` у массива, а не его содержимое:**
> ```kotlin
> 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.
Дополнительно: [Строки](../Работа%20с%20данными/Строки.md)
Далее: [Пакеты и импорты](Пакеты%20и%20импорты.md)