golang不可变货币金额与无恐慌算术汇率计算插件库money的使用
Golang不可变货币金额与无恐慌算术汇率计算插件库money的使用
简介
money是一个实现不可变货币金额和汇率的Go语言包,具有以下关键特性:
- 不可变性 - 一旦设置,金额或汇率保持不变,确保跨goroutine的安全并发访问
- 银行家舍入 - 使用半偶舍入(“银行家舍入”)来最小化金融计算中常见的累积舍入误差
- 无恐慌 - 所有方法都不会panic,在溢出、除以零或货币不匹配等情况下返回错误
- 零堆分配 - 优化以避免堆分配,减少算术操作期间的垃圾收集器影响
- 高精度 - 支持高达19位精度,表示范围从-99,999,999,999,999,999.99到99,999,999,999,999,999.99
- 正确性 - 通过广泛的模糊测试与cockroachdb/apd和shopspring/decimal包进行交叉验证
安装
要安装money包,运行以下命令:
go get github.com/govalues/money
基本使用
创建金额和汇率
package main
import (
"fmt"
"github.com/govalues/decimal"
"github.com/govalues/money"
)
func main() {
// 构造器
a, _ := money.NewAmount("USD", 8, 0) // a = $8.00
b, _ := money.ParseAmount("USD", "12.5") // b = $12.50
c, _ := money.NewAmountFromFloat64("USD", 2.567) // c = $2.567
d, _ := money.NewAmountFromInt64("USD", 7, 896, 3) // d = $7.896
r, _ := money.NewExchRate("USD", "EUR", 9, 1) // r = $/€ 0.9
x, _ := decimal.New(2, 0) // x = 2
算术运算
// 基本运算
fmt.Println(a.Add(b)) // $8.00 + $12.50
fmt.Println(a.Sub(b)) // $8.00 - $12.50
fmt.Println(a.SubAbs(b)) // abs($8.00 - $12.50)
// 乘法运算
fmt.Println(a.Mul(x)) // $8.00 * 2
fmt.Println(a.AddMul(b, x)) // $8.00 + $12.50 * 2
fmt.Println(a.SubMul(b, x)) // $8.00 - $12.50 * 2
fmt.Println(r.Conv(a)) // $8.00 * $/€ 0.9
// 除法运算
fmt.Println(a.Quo(x)) // $8.00 / 2
fmt.Println(a.AddQuo(b, x)) // $8.00 + $12.50 / 2
fmt.Println(a.SubQuo(b, x)) // $8.00 - $12.50 / 2
fmt.Println(a.QuoRem(x)) // $8.00 div 2, $8.00 mod 2
fmt.Println(a.Rat(b)) // $8.00 / $12.50
fmt.Println(a.Split(3)) // $8.00分成3部分
舍入操作
// 舍入到2位小数
fmt.Println(c.RoundToCurr()) // 2.57
fmt.Println(c.CeilToCurr()) // 2.57
fmt.Println(c.FloorToCurr()) // 2.56
fmt.Println(c.TruncToCurr()) // 2.56
转换和格式化
// 转换
fmt.Println(d.Int64(9)) // 7 896000000
fmt.Println(d.Float64()) // 7.896
fmt.Println(d.String()) // USD 7.896
// 格式化
fmt.Printf("%v", d) // USD 7.896
fmt.Printf("%[1]f %[1]c", d) // 7.896 USD
fmt.Printf("%f", d) // 7.896
fmt.Printf("%c", d) // USD
fmt.Printf("%d", d) // 790
}
性能比较
与其他流行包的比较:
特性 | govalues | rhymond v1.0.10 | bojanz v1.2.1 |
---|---|---|---|
速度 | 高 | 中 | 中 |
数值表示 | 浮点 | 定点 | 浮点 |
精度 | 19位 | 18位 | 39位 |
默认舍入 | 半偶 | 不支持 | 半上 |
溢出控制 | 是 | 否 | 是 |
支持除法 | 是 | 否 | 是 |
支持货币转换 | 是 | 否 | 是 |
基准测试
测试用例 | 表达式 | govalues | rhymond v1.0.10 | bojanz v1.2.1 | govalues vs rhymond | govalues vs bojanz |
---|---|---|---|---|---|---|
加法 | $2.00 + $3.00 | 22.95n | 218.30n | 144.10n | +851.41% | +528.02% |
乘法 | $2.00 * 3 | 21.80n | 133.40n | 239.60n | +511.79% | +998.83% |
除法(精确) | $2.00 / 4 | 80.12n | n/a | 468.05n | n/a | +484.19% |
除法(不精确) | $2.00 / 3 | 602.1n | n/a | 512.4n | n/a | -14.91% |
分割 | $2.00分成10份 | 374.9n | 897.0n | n/a | +139.28% | n/a |
转换 | $2.00转€ | 30.88n | n/a | 348.50n | n/a | +1028.38% |
基准测试结果仅供参考,实际性能可能因具体用例而异。
更多关于golang不可变货币金额与无恐慌算术汇率计算插件库money的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang不可变货币金额与无恐慌算术汇率计算插件库money的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang Money 库使用指南
money
是一个用于处理货币金额和汇率计算的 Go 语言库,它提供了不可变金额类型和无恐慌算术操作,非常适合金融应用开发。
主要特性
- 不可变金额类型,确保线程安全
- 无恐慌算术操作,避免运行时错误
- 支持多币种和汇率计算
- 精确的十进制运算
安装
go get github.com/rhymond/go-money
基本用法
创建金额
package main
import (
"fmt"
"github.com/rhymond/go-money"
)
func main() {
// 创建金额(默认货币为USD)
amount := money.New(1000, "USD") // 表示10.00美元
// 获取金额信息
fmt.Println("Amount:", amount.Amount()) // 1000
fmt.Println("Currency:", amount.Currency()) // USD
fmt.Println("Display:", amount.Display()) // $10.00
}
算术运算
// 加法
five := money.New(500, "USD")
ten := money.New(1000, "USD")
fifteen, err := five.Add(ten)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Sum:", fifteen.Display()) // $15.00
}
// 减法
diff, err := ten.Subtract(five)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Difference:", diff.Display()) // $5.00
}
// 乘法
double, err := five.Multiply(2)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Double:", double.Display()) // $10.00
}
// 除法
half, err := five.Divide(2)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Half:", half.Display()) // $2.50
}
比较操作
a := money.New(1000, "USD")
b := money.New(1500, "USD")
// 大于
if a.GreaterThan(b) {
fmt.Println("a is greater than b")
}
// 小于
if a.LessThan(b) {
fmt.Println("a is less than b") // 会执行
}
// 等于
if a.Equals(money.New(1000, "USD")) {
fmt.Println("a equals 10 USD") // 会执行
}
汇率计算
package main
import (
"fmt"
"github.com/rhymond/go-money"
)
func main() {
// 创建汇率转换器
rates := money.NewExchangeRates()
// 添加汇率(1 USD = 0.85 EUR)
err := rates.AddRate("USD", "EUR", 0.85)
if err != nil {
fmt.Println("Error adding rate:", err)
return
}
// 转换金额
usd := money.New(1000, "USD") // 10美元
eur, err := rates.Convert(usd, "EUR")
if err != nil {
fmt.Println("Error converting:", err)
return
}
fmt.Printf("%s = %s\n", usd.Display(), eur.Display()) // $10.00 = €8.50
// 批量添加汇率
rates.AddRates(map[string]map[string]float64{
"USD": {
"GBP": 0.75,
"JPY": 110.0,
},
})
// 转换为英镑
gbp, err := rates.Convert(usd, "GBP")
if err != nil {
fmt.Println("Error converting:", err)
return
}
fmt.Printf("%s = %s\n", usd.Display(), gbp.Display()) // $10.00 = £7.50
}
高级功能
分配金额
total := money.New(1000, "USD")
parts, err := total.Allocate(3, 7) // 按3:7比例分配
if err != nil {
fmt.Println("Error allocating:", err)
} else {
fmt.Println("Part 1:", parts[0].Display()) // $3.00
fmt.Println("Part 2:", parts[1].Display()) // $7.00
}
格式化输出
amount := money.New(123456, "USD")
// 自定义格式化
fmt.Println(amount.Display()) // $1,234.56
fmt.Println(amount.DisplayNoSymbol()) // 1,234.56
fmt.Println(amount.DisplayNoComma()) // $1234.56
fmt.Println(amount.DisplayNoFraction()) // $1,234
最佳实践
- 始终检查错误:虽然称为"无恐慌",但操作仍可能返回错误(如货币不匹配)
- 避免直接使用整数:使用库提供的构造函数和方法
- 考虑性能:频繁创建新对象可能影响性能,必要时可复用对象
- 处理货币精度:不同货币可能有不同的小数位数
money
库为 Go 开发者提供了安全、可靠的货币处理能力,特别适合需要精确金融计算的应用程序。