golang高性能精确货币计算插件库currency的使用
Golang高性能精确货币计算插件库currency的使用
Currency包可以帮助你进行精确的货币计算。Currency
结构体包含了定义货币所需的所有数据。
Currency结构体
type Currency struct {
// Code表示国际货币代码
Code string
// Symbol是货币符号
Symbol string
// Main表示货币的主值
Main int
// Fractional表示货币的分数/子单位
Fractional uint
// FUName是货币分数/子单位的名称,例如paise
FUName string
// FUShare表示构成1个主单位的分数/子单位数量,例如₹1 = 100 paise
FUShare uint
// PrefixSymbol如果为true,在字符串化时会前缀符号
PrefixSymbol bool
// SuffixSymbol如果为true,在字符串化时会后缀符号
SuffixSymbol bool
}
创建货币实例
New方法
func New(main int, fractional int, code, symbol string, funame string, fushare uint) *Currency
New返回基于配置创建的货币实例指针。
参数说明:
- main - 货币的主/超级单位
- fractional - 货币的子单位/分数单位
- code - 根据ISO 4217规范的货币代码
- symbol - 货币的Unicode符号
- funame - 分数/子单位的名称
- fushare - 构成1个主/超级单位的分数/子单位数量
重要!只有当主值为0时,分数单位才可以是负数。如果主值不为0,分数单位的负号将被忽略。
解析器和便捷方法
NewFractional(fractional int, symbol string, fulabel string, fushare uint)
- 给定货币的总值(由分数单位表示),返回货币结构实例ParseString(value string, code, symbol string, fulabel string, fushare uint)
- 给定表示为字符串的货币值,返回货币结构实例ParseFloat64(value float64, code, symbol string, funame string, fushare uint)
- 给定表示为float64的货币值,返回货币结构实例
计算方法
重要:计算仅支持相同类型的货币(即货币代码必须匹配)
c1.Add(c2 currency)
- 将c2加到c1,并更新c1c1.AddInt(main int, fractional int)
- 将相当于main和fractional int的货币值加到c1c1.Subtract(c2 currency)
- 从c1中减去c2,并更新c1c1.SubtractIn(main int, fractional int)
- 从c1中减去相当于main和fractional int的货币值c1.Multiply(n int)
- 将c1乘以整数nc1.MultiplyFloat64(n float64)
- 将c1乘以浮点数nc1.UpdateWithFractional(ftotal int)
- 更新c1的值,其中ftotal是分数单位中的货币总值c1.FractionalTotal() int
- 返回分数单位中的货币总值c1.Percent(n float64) currency
- 返回一个新的货币实例,它是c1的n百分比c1.Allocate(n int, retain bool)[]currency, ok
- 返回大小为n的货币切片。如果ok为true表示货币值可以被n完全整除。如果retain为true,则c1将保留分配后的余数值,否则余数将分布在返回的货币中。
完整示例
package main
import (
"fmt"
"github.com/naughtygopher/currency"
)
func main() {
// 创建INR货币实例(1卢比=100派萨)
inr := currency.New(1, 0, "INR", "₹", "paise", 100)
fmt.Println(inr.String()) // 输出: ₹1.00
// 从字符串解析
inrFromStr, _ := currency.ParseString("123.45", "INR", "₹", "paise", 100)
fmt.Println(inrFromStr.String()) // 输出: ₹123.45
// 从浮点数解析
inrFromFloat := currency.ParseFloat64(456.78, "INR", "₹", "paise", 100)
fmt.Println(inrFromFloat.String()) // 输出: ₹456.78
// 加法运算
inr1 := currency.New(100, 50, "INR", "₹", "paise", 100)
inr2 := currency.New(50, 25, "INR", "₹", "paise", 100)
inr1.Add(*inr2)
fmt.Println(inr1.String()) // 输出: ₹150.75
// 乘法运算
inr3 := currency.New(10, 0, "INR", "₹", "paise", 100)
inr3.Multiply(5)
fmt.Println(inr3.String()) // 输出: ₹50.00
// 百分比计算
inr4 := currency.New(200, 0, "INR", "₹", "paise", 100)
tenPercent := inr4.Percent(10)
fmt.Println(tenPercent.String()) // 输出: ₹20.00
// 分配计算
inr5 := currency.New(1, 0, "INR", "₹", "paise", 100)
parts, ok := inr5.Allocate(3, false)
fmt.Println(ok) // 输出: false (因为1卢比不能被3整除)
for i, part := range parts {
fmt.Printf("Part %d: %s\n", i+1, part.String())
}
// 输出:
// Part 1: ₹0.34
// Part 2: ₹0.33
// Part 3: ₹0.33
}
性能基准测试
在MacBook Pro (13-inch, M3, 2024)上运行的基准测试结果:
go version go1.23.1 darwin/arm64
BenchmarkNew-8 55541650 21.68 ns/op
BenchmarkNewFractional-8 58322852 21.69 ns/op
BenchmarkParseFloat64-8 47724391 25.72 ns/op
BenchmarkParseString-8 6650085 182.2 ns/op
BenchmarkString-8 20838006 58.65 ns/op
BenchmarkStringNoPrefix-8 30418314 39.87 ns/op
BenchmarkFloat64-8 1000000000 0.2722 ns/op
BenchmarkFractionalTotal-8 1000000000 0.2697 ns/op
BenchmarkUpdateWithFractional-8 1000000000 1.068 ns/op
BenchmarkAdd-8 190538139 6.245 ns/op
BenchmarkAddInt-8 230544486 5.690 ns/op
BenchmarkSubtract-8 185860339 6.537 ns/op
BenchmarkSubtractInt-8 217542852 5.571 ns/op
BenchmarkMultiply-8 282455095 4.335 ns/op
BenchmarkMultiplyFloat64-8 84543258 13.13 ns/op
BenchmarkPercent-8 52612252 21.28 ns/op
BenchmarkAllocate-8 35645416 34.41 ns/op
重要!此包不支持非10的幂的子单位,也不支持具有多个子单位的货币。
更多关于golang高性能精确货币计算插件库currency的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang高性能精确货币计算插件库currency的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang 高性能精确货币计算插件库 currency 使用指南
在金融和电商应用中,精确的货币计算至关重要。Go 语言的 currency
库是一个高性能的货币处理库,支持精确的货币运算和格式化。下面我将详细介绍如何使用这个库。
安装 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)
}
fmt.Println(amount) // 输出: USD 1234.56
// 从整数创建金额 (以最小货币单位,如美分)
amount = currency.NewAmountFromInt64(123456, "USD")
fmt.Println(amount) // 输出: USD 1234.56
}
2. 货币运算
func main() {
// 加法
a, _ := currency.NewAmount("100.50", "USD")
b, _ := currency.NewAmount("50.25", "USD")
sum, err := currency.Add(a, b)
if err != nil {
panic(err)
}
fmt.Println(sum) // 输出: USD 150.75
// 减法
diff, err := currency.Subtract(a, b)
if err != nil {
panic(err)
}
fmt.Println(diff) // 输出: USD 50.25
// 乘法 (乘以标量)
product, err := currency.Multiply(a, 2)
if err != nil {
panic(err)
}
fmt.Println(product) // 输出: USD 201.00
// 除法 (除以标量)
quotient, err := currency.Divide(a, 2)
if err != nil {
panic(err)
}
fmt.Println(quotient) // 输出: USD 50.25
}
3. 货币比较
func main() {
a, _ := currency.NewAmount("100.00", "USD")
b, _ := currency.NewAmount("50.00", "USD")
// 比较
fmt.Println(currency.Compare(a, b)) // 输出: 1 (a > b)
fmt.Println(currency.Equals(a, b)) // 输出: false
fmt.Println(currency.LessThan(a, b)) // 输出: false
}
4. 货币格式化
func main() {
amount, _ := currency.NewAmount("1234.56", "USD")
// 创建格式化器
locale := currency.NewLocale("en-US")
formatter := currency.NewFormatter(locale)
// 格式化输出
fmt.Println(formatter.Format(amount)) // 输出: $1,234.56
// 其他地区格式
deFormatter := currency.NewFormatter(currency.NewLocale("de-DE"))
fmt.Println(deFormatter.Format(amount)) // 输出: 1.234,56 $
}
5. 货币转换
func main() {
// 创建转换器
converter := currency.NewConverter(
currency.WithRates(map[string]map[string]string{
"USD": {"EUR": "0.85", "GBP": "0.72"},
"EUR": {"USD": "1.18", "GBP": "0.85"},
}),
)
amount, _ := currency.NewAmount("100.00", "USD")
// 转换货币
eurAmount, err := converter.Convert(amount, "EUR")
if err != nil {
panic(err)
}
fmt.Println(eurAmount) // 输出: EUR 85.00
}
高级特性
1. 自定义舍入规则
func main() {
// 默认舍入规则 (银行家舍入法)
amount, _ := currency.NewAmount("100.555", "USD")
fmt.Println(amount) // 输出: USD 100.56
// 自定义舍入规则
customRounding := currency.Rounding{
Increment: 5, // 舍入到最接近的5美分
Mode: currency.RoundHalfUp,
}
amount, _ = currency.NewAmountWithRounding("100.52", "USD", customRounding)
fmt.Println(amount) // 输出: USD 100.55
}
2. 处理多种货币
func main() {
// 创建不同货币的金额
usd, _ := currency.NewAmount("100.00", "USD")
eur, _ := currency.NewAmount("85.00", "EUR")
// 确保货币相同才能运算
sum, err := currency.Add(usd, eur)
if err != nil {
fmt.Println("不能直接相加不同货币:", err)
}
// 需要先转换货币
converter := currency.NewConverter(
currency.WithRates(map[string]map[string]string{
"USD": {"EUR": "0.85"},
}),
)
eurConverted, _ := converter.Convert(usd, "EUR")
sum, _ = currency.Add(eurConverted, eur)
fmt.Println(sum) // 输出: EUR 170.00
}
性能优化建议
- 重用对象:Formatter 和 Converter 可以重用,避免重复创建
- 预加载汇率:一次性加载所有需要的汇率数据
- 使用整数运算:对于大量计算,使用 NewAmountFromInt64 可能更高效
总结
currency 库提供了强大的货币处理能力,包括:
- 精确的货币计算(基于 decimal 实现)
- 多货币支持
- 货币转换
- 本地化格式化
- 自定义舍入规则
这个库特别适合需要处理金融数据、电子商务价格计算等场景,能够避免浮点数计算带来的精度问题。
希望这个指南能帮助你快速上手使用 currency 库进行精确的货币计算!