Какой тип данных в Go лучше всего подходит для хранения денежных сумм, и почему `float` является плохим выбором?

Ответ

Для работы с деньгами следует избегать типов с плавающей запятой (float32, float64) из-за их неточности в представлении десятичных дробей. Лучшими практиками являются:

1. int (в минимальных единицах)

Хранить сумму в минимальных денежных единицах (копейках, центах). Это самый простой, быстрый и распространенный подход.

  • Преимущества: Высокая производительность, простота, отсутствие проблем с точностью, возможность использовать в качестве ключа map.
  • Недостатки: Требуется ручное преобразование при отображении пользователю (деление на 100).
// 123 рубля 45 копеек хранятся как 12345
priceInKopecks := 12345

// Для отображения
fmt.Printf("Цена: %.2f руб.n", float64(priceInKopecks)/100.0)

2. Специализированные пакеты (decimal)

Использовать библиотеки для работы с десятичной арифметикой с фиксированной точностью. Самая популярная — github.com/shopspring/decimal.

  • Преимущества: Гарантированная точность, удобные методы для арифметических операций (сложение, вычитание, округление).
  • Недостатки: Ниже производительность по сравнению с int, добавляет внешнюю зависимость, экземпляры decimal.Decimal не являются сравниваемыми и не могут быть ключами в map.
import "github.com/shopspring/decimal"

price1, _ := decimal.NewFromString("100.50")
price2 := decimal.NewFromFloat(0.2)

// Точное сложение
total := price1.Add(price2) // "100.7"

Почему float — плохой выбор?

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

// Классический пример
fmt.Println(0.1 + 0.2) // Выведет: 0.30000000000000004

// При работе с деньгами это недопустимо
var price float64 = 100.50
var tax float64 = 0.21
fmt.Println(price * tax) // Выведет: 21.105000000000004

Ответ 18+ 🔞

А, ну ты глянь, какие тут советы по деньгам раздают! Слушай, это же просто пиздец, как люди умудряются накосячить с баблом в коде. Ну ладно, сейчас разложу по полочкам, как не облажаться.

Во-первых, забудь нахуй про эти float'ы, когда речь про деньги. Это как пытаться измерить граммы на весах для грузовиков — нихуя точности не будет. Вот смотри, классика жанра:

fmt.Println(0.1 + 0.2) // Выведет: 0.30000000000000004

Ёпта, ну что это за пиздец? Ты представляешь, если бы в магазине тебе сдачу так считали? "С вас 0.30000000000000004 рубля, гражданин". Да я бы кассу разнёс, блядь!

1. Самый простой и надёжный способ — int в копейках

Это как работать голыми руками, зато точно и быстро. Всё хранишь в минимальных единицах — копейках, центах, сатоши, чёрт знает в чём ещё.

  • Что хорошего: Быстрее некуда, никаких проблем с точностью, можно хоть в map ключом пихать.
  • Что не очень: Надо постоянно делить на 100, когда показываешь людям. Ну, терпимо, блядь.
// 123 рубля 45 копеек — это просто 12345
priceInKopecks := 12345

// А чтобы показать — подели на сотку
fmt.Printf("Цена: %.2f руб.n", float64(priceInKopecks)/100.0)

Вот и вся магия. Никаких сюрпризов, всё прозрачно, как слёзы ребёнка. Хочешь прибавить 50 копеек? priceInKopecks += 50. И нехуй мудохаться.

2. Для сложных расчётов — пакеты вроде decimal

Если у тебя там проценты, сложные проценты, налоги на налоги — тогда уже можно прикрутить что-то серьёзное. github.com/shopspring/decimal — народный выбор.

  • Что хорошего: Точность гарантирована, как у швейцарских часов. Сложение, умножение, округление — всё из коробки.
  • Что не очень: Тормознее, чем int, ещё и зависимость подтягивать. И вот это вот — в map их не засунешь, они не сравниваемые. Ну, ебать, не судьба.
import "github.com/shopspring/decimal"

price1, _ := decimal.NewFromString("100.50")
price2 := decimal.NewFromFloat(0.2)

// Складываешь — и спишь спокойно
total := price1.Add(price2) // "100.7"

Итог, блядь

Не выёбывайся. Для 99% случаев — int в копейках, и все довольны. Если реально сложная финансовая хуйня с кучей расчётов — тогда decimal. А float для денег — это как ебать гвоздями: и больно, и бесполезно, и результат предсказуемо пиздецовый.

Вот так-то, а то некоторые думают, что они умные, с этими своими числами с плавающей запятой. Плавать они будут, только не в деньгах, а в говне, когда клиенты начнут жаловаться на копейку в расчётах.