golang高性能精确货币计算插件库currency的使用

Golang高性能精确货币计算插件库currency的使用

webgo gopher

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,分数单位的负号将被忽略。

解析器和便捷方法

  1. NewFractional(fractional int, symbol string, fulabel string, fushare uint) - 给定货币的总值(由分数单位表示),返回货币结构实例
  2. ParseString(value string, code, symbol string, fulabel string, fushare uint) - 给定表示为字符串的货币值,返回货币结构实例
  3. ParseFloat64(value float64, code, symbol string, funame string, fushare uint) - 给定表示为float64的货币值,返回货币结构实例

计算方法

重要:计算仅支持相同类型的货币(即货币代码必须匹配)

  1. c1.Add(c2 currency) - 将c2加到c1,并更新c1
  2. c1.AddInt(main int, fractional int) - 将相当于main和fractional int的货币值加到c1
  3. c1.Subtract(c2 currency) - 从c1中减去c2,并更新c1
  4. c1.SubtractIn(main int, fractional int) - 从c1中减去相当于main和fractional int的货币值
  5. c1.Multiply(n int) - 将c1乘以整数n
  6. c1.MultiplyFloat64(n float64) - 将c1乘以浮点数n
  7. c1.UpdateWithFractional(ftotal int) - 更新c1的值,其中ftotal是分数单位中的货币总值
  8. c1.FractionalTotal() int - 返回分数单位中的货币总值
  9. c1.Percent(n float64) currency - 返回一个新的货币实例,它是c1的n百分比
  10. 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
}

性能优化建议

  1. 重用对象:Formatter 和 Converter 可以重用,避免重复创建
  2. 预加载汇率:一次性加载所有需要的汇率数据
  3. 使用整数运算:对于大量计算,使用 NewAmountFromInt64 可能更高效

总结

currency 库提供了强大的货币处理能力,包括:

  • 精确的货币计算(基于 decimal 实现)
  • 多货币支持
  • 货币转换
  • 本地化格式化
  • 自定义舍入规则

这个库特别适合需要处理金融数据、电子商务价格计算等场景,能够避免浮点数计算带来的精度问题。

希望这个指南能帮助你快速上手使用 currency 库进行精确的货币计算!

回到顶部