Avatar ·

Форматирование строк в Kotlin: как вывести числа с плавающей точкой и проценты?

Всем привет! Я только начал изучать Kotlin и столкнулся с проблемой форматирования строк. В Java я привык использовать `String.format("%.2f", value)` или `System.out.printf()`, но в Kotlin это работает не так, как я ожидал. Вот пример. Я пишу простой калькулятор для подсчёта скидки. У меня есть цена товара и процент скидки, я хочу вывести итоговую сумму с двумя знаками после запятой и сам процент в виде "15%". ```kotlin fun main() { val price = 1250.0 val discount = 15 val finalPrice = price * (100 - discount) / 100 // Пытаюсь вывести как в Java println(String.format("Цена со скидкой: %.2f", finalPrice)) println(String.format("Скидка: %d%%", discount)) } ``` Вроде бы работает, но я слышал, что в Kotlin есть более идиоматичные способы. Кроме того, когда я пытаюсь использовать шаблоны строк с долларом (`$`), я не могу применить форматирование: ```kotlin println("Цена: $finalPrice") // выводит много знаков после запятой ``` Как правильно форматировать строки в Kotlin? Есть ли встроенные функции, похожие на `printf`? И как быть, если нужно вывести символ процента в шаблонной строке? Заранее спасибо за помощь! <<>>

Основные способы форматирования строк в Kotlin

В Kotlin есть несколько подходов к форматированию строк. Рассмотрим их от простых к более продвинутым, с акцентом на идиоматичность и читаемость кода.

1. Функция String.format() (Java-стиль)

Самый прямолинейный способ — использовать знакомую Java-функцию. Kotlin полностью поддерживает её, но есть нюанс: вы можете вызывать её как статический метод класса String или как extension-функцию для самого форматируемого объекта.

val finalPrice = 1062.50
val discount = 15

// Вариант 1: статический вызов (как в Java)
println(String.format("Цена со скидкой: %.2f", finalPrice))

// Вариант 2: extension-функция (более Kotlin-стиль)
println("%.2f".format(finalPrice))  // "1062.50"

// Форматирование нескольких аргументов
println("Скидка: %d%%".format(discount))  // "Скидка: 15%"

Обратите внимание на двойной знак процента (%%) — это стандартный способ вывести символ % в форматной строке.

2. Шаблонные строки с $ (самый идиоматичный способ)

В Kotlin предпочтительнее использовать строковые шаблоны. Они не поддерживают форматирование напрямую, но вы можете комбинировать их с функциями преобразования чисел.

// Простое выражение с долларом
println("Цена: $finalPrice")  // "Цена: 1062.5" (много знаков)

// Форматирование через .format() внутри шаблона
println("Цена со скидкой: ${"%.2f".format(finalPrice)}")
println("Скидка: $discount%")  // Просто добавляем символ % в конец

// Для сложных выражений используйте фигурные скобки
val percent = 15.5
println("Скидка: ${"%.1f".format(percent)}%")  // "Скидка: 15.5%"

Этот способ удобен, когда нужно вставить форматированное значение прямо в середину строки без создания дополнительных переменных.

3. Использование DecimalFormat для чисел

Для более сложного форматирования чисел (например, с разделителями групп или валютами) лучше использовать java.text.DecimalFormat:

import java.text.DecimalFormat

val df = DecimalFormat("#,##0.00")
println("Цена: ${df.format(finalPrice)}")  // "Цена: 1 062,50" (зависит от локали)

// Для процентов
val percentFormat = DecimalFormat("#0.##%")
println("Скидка: ${percentFormat.format(discount / 100.0)}")  // "Скидка: 15%"

Обратите внимание: DecimalFormat для процентов ожидает значение в долях (0.15 для 15%), поэтому нужно делить на 100.

4. Extension-функции для удобства

Вы можете создать свои функции-расширения, чтобы сделать код ещё чище:

fun Double.toPriceFormat(): String = "%.2f".format(this)
fun Int.toPercentFormat(): String = "$this%"

// Использование
println("Цена: ${finalPrice.toPriceFormat()}")
println("Скидка: ${discount.toPercentFormat()}")

Итоговые рекомендации

  • Для простых случаев — используйте шаблонные строки с $ и встроенным .format().
  • Для локализованного вывода (валюты, даты) — используйте DecimalFormat или SimpleDateFormat.
  • Для консольного вывода (отладка) — можно использовать println(String.format(...)) как быстрый вариант.
  • Избегайте смешивания % и $ в одной строке — это ухудшает читаемость.

В вашем примере с калькулятором самый идиоматичный код будет выглядеть так:

fun main() {
    val price = 1250.0
    val discount = 15
    val finalPrice = price * (100 - discount) / 100
    
    println("Цена со скидкой: ${"%.2f".format(finalPrice)}")
    println("Скидка: $discount%")
}

Этот код читается естественно и не требует импорта дополнительных классов.

<<>>

Альтернативный подход: использование println с форматированием через System.out.printf

Если вы привыкли к C-стилю форматирования, в Kotlin можно напрямую использовать System.out.printf():

val finalPrice = 1062.50
val discount = 15

System.out.printf("Цена со скидкой: %.2f%n", finalPrice)
System.out.printf("Скидка: %d%%%n", discount)

Важно: System.out.printf() не добавляет перевод строки автоматически, поэтому нужно использовать %n или \n. В отличие от println, это функция для форматированного вывода, а не для создания строки.

Когда это может быть полезно?

  • При миграции кода с Java на Kotlin — не нужно переписывать все форматирования.
  • В консольных утилитах, где важна производительность (меньше создаётся промежуточных строк).
  • При работе с StringBuilder или PrintWriter.

Недостатки

  • Менее идиоматично для Kotlin.
  • Нельзя использовать внутри строковых шаблонов.
  • Требует явного указания локали для чисел с плавающей точкой (по умолчанию используется системная локаль).

В большинстве случаев я рекомендую придерживаться первого ответа — использовать .format() или шаблонные строки, так как это более естественно для Kotlin и лучше читается.