Added kotlin guide. (WIP) (15.10.26)
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user