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 开发者提供了安全、可靠的货币处理能力,特别适合需要精确金融计算的应用程序。

回到顶部