golang货币金额处理与格式化插件库currency的使用
Golang货币金额处理与格式化插件库currency的使用
功能特性
- 所有货币代码、数字代码和小数位数
- 所有地区的货币符号和格式
- 国家映射(国家代码=>货币代码)
- Amount结构体,具有值语义(Fowler的Money模式)
- Formatter,用于格式化金额和解析格式化后的金额
基本使用示例
package main
import (
"fmt"
"github.com/bojanz/currency"
)
func main() {
// 创建一个欧元金额
amount, _ := currency.NewAmount("275.98", "EUR")
// 金额乘以4
total, _ := amount.Mul("4")
// 创建法语地区格式化器
locale := currency.NewLocale("fr")
formatter := currency.NewFormatter(locale)
fmt.Println(formatter.Format(total)) // 输出: 1 103,92 €
// 将金额转换为伊朗里亚尔并以波斯语显示
total, _ = total.Convert("IRR", "45.538")
total = total.Round()
locale = currency.NewLocale("fa")
formatter = currency.NewFormatter(locale)
fmt.Println(formatter.Format(total)) // 输出: ریال ۵۰٬۲۷۰
}
设计目标
底层使用真正的十进制实现
货币金额不能是浮点数。存储整数小数单位(如2.99=>299)在多种货币或需要亚小数单位精度时会变得有问题。因此使用了cockroachdb/apd包提供的任意精度十进制类型。
智能过滤CLDR数据
使用了CLDR的"现代"子集,从约560个地区减少到约370个。
易于比较
Amount结构体可以通过内置的Equal()方法与google/go-cmp进行比较。
可与PostgreSQL复合类型一起使用
由于实现了driver.Valuer和sql.Scanner接口,使用pgx驱动的应用程序可以将金额存储在复合类型中。
PostgreSQL集成示例
数据库Schema
CREATE TYPE price AS (
number NUMERIC,
currency_code TEXT
);
CREATE TABLE products (
id CHAR(26) PRIMARY KEY,
name TEXT NOT NULL,
price price NOT NULL,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ
);
Go结构体
type Product struct {
ID string
Name string
Price currency.Amount
CreatedAt time.Time
UpdatedAt time.Time
}
查询示例
p := Product{}
row := tx.QueryRow(ctx, `SELECT id, name, price, created_at, updated_at FROM products WHERE id = $1`, id)
err := row.Scan(&p.ID, &p.Name, &p.Price, &p.CreatedAt, &p.UpdatedAt)
这个currency库提供了完整的货币处理能力,包括创建金额、数学运算、货币转换和地区化格式化等功能,是处理国际化货币需求的理想选择。
更多关于golang货币金额处理与格式化插件库currency的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang货币金额处理与格式化插件库currency的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang 货币金额处理与格式化:currency 库使用指南
在 Go 语言中处理货币金额时,使用专门的库可以避免浮点数精度问题并提供更好的格式化功能。currency
是一个优秀的 Go 库,专门用于货币金额的处理和格式化。
安装 currency 库
go get -u github.com/bojanz/currency
基本使用
1. 创建金额对象
package main
import (
"fmt"
"github.com/bojanz/currency"
)
func main() {
// 从字符串创建金额
amount, err := currency.NewAmount("1234.56", "USD")
if err != nil {
panic(err)
}
// 从整数创建金额 (以分为单位)
amount2 := currency.NewAmountFromInt64(123456, "USD", 2) // 1234.56 USD
fmt.Println(amount.String()) // 输出: 1234.56 USD
fmt.Println(amount2.String()) // 输出: 1234.56 USD
}
2. 金额运算
func main() {
a, _ := currency.NewAmount("100.50", "USD")
b, _ := currency.NewAmount("50.25", "USD")
// 加法
sum, err := a.Add(b)
if err != nil {
panic(err)
}
fmt.Println("Sum:", sum) // 输出: Sum: 150.75 USD
// 减法
diff, err := a.Sub(b)
if err != nil {
panic(err)
}
fmt.Println("Difference:", diff) // 输出: Difference: 50.25 USD
// 乘法 (乘以标量)
product, err := a.Mul(2)
if err != nil {
panic(err)
}
fmt.Println("Product:", product) // 输出: Product: 201.00 USD
// 除法 (除以标量)
quotient, err := a.Div(2)
if err != nil {
panic(err)
}
fmt.Println("Quotient:", quotient) // 输出: Quotient: 50.25 USD
}
3. 金额比较
func main() {
a, _ := currency.NewAmount("100.00", "USD")
b, _ := currency.NewAmount("50.00", "USD")
c, _ := currency.NewAmount("100.00", "USD")
fmt.Println(a.Equal(b)) // false
fmt.Println(a.Equal(c)) // true
fmt.Println(a.GreaterThan(b)) // true
fmt.Println(a.LessThan(b)) // false
}
高级功能
1. 格式化金额
func main() {
amount, _ := currency.NewAmount("1234.56", "USD")
// 创建格式化器
formatter := currency.NewFormatter(amount)
// 设置格式选项
formatter.NoGrouping(false) // 使用千位分隔符
formatter.SetSymbol(currency.SymbolShow) // 显示货币符号
// 格式化输出
fmt.Println(formatter.Format()) // 输出: $1,234.56
// 不同地区的格式化
locale := currency.NewLocale("de-DE")
eurAmount, _ := currency.NewAmount("1234.56", "EUR")
deFormatter := currency.NewFormatter(eurAmount, locale)
fmt.Println(deFormatter.Format()) // 输出: 1.234,56 €
}
2. 货币转换
func main() {
// 创建汇率提供者
rates := currency.NewRates()
// 添加汇率 (1 USD = 0.85 EUR)
rates.SetRate("USD", "EUR", 0.85)
// 转换金额
usdAmount, _ := currency.NewAmount("100.00", "USD")
eurAmount, err := rates.Convert(usdAmount, "EUR")
if err != nil {
panic(err)
}
fmt.Println(eurAmount) // 输出: 85.00 EUR
}
3. 处理不同货币
func main() {
usd, _ := currency.NewAmount("100.00", "USD")
eur, _ := currency.NewAmount("85.00", "EUR")
// 检查货币是否相同
if usd.CurrencyCode() == eur.CurrencyCode() {
fmt.Println("Same currency")
} else {
fmt.Println("Different currencies") // 输出: Different currencies
}
// 转换为相同货币再比较
rates := currency.NewRates()
rates.SetRate("USD", "EUR", 0.85)
eurConverted, _ := rates.Convert(usd, "EUR")
if eurConverted.Equal(eur) {
fmt.Println("Amounts are equal after conversion") // 输出: Amounts are equal after conversion
}
}
最佳实践
-
始终使用 currency 库处理货币金额,避免使用 float64 或 float32,以防止精度问题。
-
尽早验证货币代码:
if !currency.IsValid("USDD") { // 注意: 错误的货币代码 fmt.Println("Invalid currency code") }
-
处理运算错误:
result, err := amount1.Add(amount2) if err != nil { // 可能是货币不匹配或其他错误 return fmt.Errorf("failed to add amounts: %w", err) }
-
考虑使用上下文保存格式化选项:
func formatForUser(amount currency.Amount, locale string) string { loc := currency.NewLocale(locale) formatter := currency.NewFormatter(amount, loc) formatter.NoGrouping(false) return formatter.Format() }
currency 库提供了强大而灵活的货币处理功能,适合电子商务、金融应用等需要精确货币计算的场景。通过合理使用这个库,可以避免常见的货币处理陷阱,并确保应用程序在全球范围内正确显示和处理货币金额。