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

最佳实践

  1. 始终检查错误:虽然称为"无恐慌",但操作仍可能返回错误(如货币不匹配)
  2. 避免直接使用整数:使用库提供的构造函数和方法
  3. 考虑性能:频繁创建新对象可能影响性能,必要时可复用对象
  4. 处理货币精度:不同货币可能有不同的小数位数

money 库为 Go 开发者提供了安全、可靠的货币处理能力,特别适合需要精确金融计算的应用程序。

回到顶部