[英]Which Swift datatype do I use for currency
I have an iOS application that will be performing a lot of basic arithmetic on numbers representing USD currency (eg 25.00 representing $25.00).我有一个 iOS 应用程序,它将对表示美元货币的数字(例如 25.00 表示 25.00 美元)执行大量基本算术运算。
I have gotten into a lot of trouble using the datatype Double in other languages like Java and Javascript so I would like to know the best datatype to use for currency in Swift.我在 Java 和 Javascript 等其他语言中使用数据类型 Double 遇到了很多麻烦,所以我想知道 Swift 中用于货币的最佳数据类型。
Use Decimal
, and make sure you initialize it properly !使用
Decimal
,并确保正确初始化它!
// Initialising a Decimal from a Double:
let monetaryAmountAsDouble = 32.111
let decimal: Decimal = NSNumber(floatLiteral: 32.111).decimalValue
print(decimal) // 32.111 😀
let result = decimal / 2
print(result) // 16.0555 😀
// Initialising a Decimal from a String:
let monetaryAmountAsString = "32,111.01"
let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "en_US")
formatter.numberStyle = .decimal
if let number = formatter.number(from: monetaryAmountAsString) {
let decimal = number.decimalValue
print(decimal) // 32111.01 😀
let result = decimal / 2.1
print(result) // 15290.9571428571428571428571428571428571 😀
}
let monetaryAmountAsDouble = 32.111
let decimal = Decimal(monetaryAmountAsDouble)
print(decimal) // 32.11099999999999488 😟
let monetaryAmountAsString = "32,111.01"
if let decimal = Decimal(string: monetaryAmountAsString, locale: Locale(identifier: "en_US")) {
print(decimal) // 32 😟
}
Performing arithmetic operations on Double
s or Float
s representing currency amounts will produce inaccurate results.对表示货币金额的
Double
s 或Float
s 执行算术运算将产生不准确的结果。 This is because the Double
and Float
types cannot accurately represent most decimal numbers.这是因为
Double
和Float
类型不能准确表示大多数十进制数。 More information here .更多信息在这里。
Bottom line: Perform arithmetic operations on currency amounts using Decimal
s or Int
底线:使用
Decimal
s 或Int
对货币金额执行算术运算
There's a really nice lib called Money :有一个非常好的库,名为Money :
let money: Money = 100
let moreMoney = money + 50 //150
There a lot of nice features besides that, such as type-safe currencies:除此之外还有很多不错的功能,例如类型安全的货币:
let euros: EUR = 100
let dollars: USD = 1500
euros + dollars //Error
Binary operator '+' cannot be applied to operands of type 'EUR' (aka '_Money') and 'USD' (aka '_Money')
二元运算符“+”不能应用于“EUR”(又名“_Money”)和“USD”(又名“_Money”)类型的操作数
The Flight-School/Money is probably the best choice for a project full of monies. Flight-School/Money可能是资金充裕的项目的最佳选择。
In theending of README @mattt provides a nice solution for a simple Money type:在README的结尾@mattt 为简单的 Money 类型提供了一个很好的解决方案:
struct Money {
enum Currency: String {
case USD, EUR, GBP, CNY // supported currencies here
}
var amount: Decimal
var currency: Currency
}
Chapter 3 in 'Flight School Guide to Swift Numbers' is provides excellent intro into the topic. 'Flight School Guide to Swift Numbers' 中的第 3 章提供了对该主题的出色介绍。
We use this approach with Currency
being a huge enum that has been generated in advance (don't forget a monetary value is just a number without its currency - they both belong together):我们使用这种方法将
Currency
用作一个预先生成的巨大枚举(不要忘记货币价值只是一个没有货币的数字 - 它们都属于一起):
struct Money: Hashable, Equatable {
let value: Decimal
let currency: Currency
}
extension Money {
var string: String {
CurrencyFormatter.shared.string(from: self)
}
}
You need the Decimal
and its initializer:您需要
Decimal
及其初始值设定项:
Decimal(string: "12345.67890", locale: Locale(identifier: "en-US"))
When considering the other answers, please note that Float
and Double
literals affect the accuracy of the Decimal result.在考虑其他答案时,请注意
Float
和Double
文字会影响 Decimal 结果的准确性。 The same applies to the NumberFormatter
.这同样适用于
NumberFormatter
。
Decimal(5.01) // 5.009999999999998976 ❌
Decimal(floatLiteral: 5.01) // 5.009999999999998976 ❌
NSNumber(floatLiteral: 0.9999999).decimalValue // 0.9999999000000001 ❌
let decimalFormatter = NumberFormatter()
decimalFormatter.numberStyle = .decimal
decimalFormatter.number(from: "0.9999999")?.decimalValue // 0.9999999000000001 ❌
Decimal(string: "5.01", locale: Locale(identifier: "en-US")) // 5.01 ✅
Decimal(string: "0.9999999", locale: Locale(identifier: "en-US")) // 0.9999999 ✅
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.