RoundedDecimal 有两种形式:RoundedDecimal<T: DecimalPlaces>
和 DynamicRoundedDecimal
。不同的情况需要使用其中一种。
Swift 中,小数位数明确地作为类型的一部分。例如,RoundedDecimal<Places.five>
只能与其他 RoundedDecimal<Places.five>
值进行运算。这在编译时得到保证,但要求开发者预先知道所需的精度级别。
// listedPrice == 2.59
let listedPrice: RoundedDecimal<Places.two> = "2.5872659"
// exchangePrice == 1.12345
let exchangeRate: RoundedDecimal<Places.five> = "1.1234528492"
let localPrice = listedPrice * exchangeRate
将会导致编译失败
binary operator '*' cannot be applied to operands of type 'RoundedDecimal<Places.two>' and 'RoundedDecimal<Places.five>'
let localPrice = listedPrice * exchangeRate
~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
这些情况是可以处理的,但开发者必须在允许乘法运算之前,明确决定最终的精度。有关更多信息,请参见 RoundedDecimal
的文档。
当需要的位数在编译时未知时,此类型非常有用。例如,当处理运行时决定的任意货币时,这些货币具有不同的小数位数。 美元有 2 位小数,但日元有 0 位小数。 DynamicRoundedDecimal
适用于这种情况,因为所需的位数是在构造时提供的。
// listedPrice == 2.59 after using a scale of 2 to represent USD
let listedPrice = DynamicRoundedDecimal(stringLiteral: "2.5872659", scale: 2)
// exchangePrice == 108.09364 after using a scale of 5
let exchangeRate = DynamicRoundedDecimal(stringLiteral: "108.0936412", scale: 5)
// localPrice = 279.96253 which uses the largest scale of either decimal, 5 in this case
let localPrice = listedPrice * exchangeRate
// appropriateLocalPrice = 280 after using a scale of 0 to represent JPY
let appropriateLocalPrice = localPrice.with(scale: 0)
dependencies: [
.package(url: "https://github.com/SoftwareEngineerChris/RoundedDecimal.git", from: "2.2.0")
]
TL/DR: 我们希望保证一个精度级别,或者在更改通过我们系统的小数的精度级别时,明确地进行声明。
在处理小数时,我们经常想知道;处理;或者在我们要表示的数字中维护一定数量的位数。
例如,当在为英国和美国服务的购物应用程序中处理货币时,我们希望处理有 2 位小数的数字。尤其是在处理大量这些数字并在美元和英镑之间进行转换时。
如果我们有一个在英国销售成本为 *£2.50* 的产品,并且我们想在美国销售它,我们可能想使用汇率来计算当地价格。 如果我们的 API 提供的汇率为 *每美元 0.81245 英镑* (或 *每英镑 1.23084 美元*),使用简单的乘法,我们可能会计算出该商品在美国的价格为 *$3.0771*。
我们可能不想向我们的用户显示 *$3.0771*,因为他们通常不会处理美分的几分之一。在我们的展示层中,我们*可能*将收据中的值格式化为 *$3.08*。
用户已决定订购 *300* 件商品。 我们的应用程序中的计算不一定知道数据的展示方式,因此处理商品价格 *$3.0771*。 因此,*$3.0771* 乘以 *300* 等于 *$923.13*。
在这种情况下,我们可能会向用户展示一个看起来像这样的收据:Special Product @ £3.08 x 300 = £923.13
除了 *300* 乘以 *$3.08* 不是 *$923.13*。 而是 *$924.00*。 用户对向他们展示的总数感到困惑,没有意识到该计算使用每件商品 $3.0771 而不是 $3.08 的价格。
他们应该在收据上看到的是:Special Product @ $3.08 x 300 = $924.00
或 Special Product @ $3.0771 x 300 = $923.13
如何处理这应该是一个商业决定,但我们应该能够在我们的代码中保证该决定的结果。 如果使用的货币,或者至少需要的位数长度,是静态的并且在编译时已知,我们可以使用 RoundedDecimal
使其成为编译时的要求。 或者,如果我们处理的是运行时选择的货币或位数长度,我们可以使用 DynamicRoundedDecimal
来处理。 有关如何处理的更多信息,请参阅每种类型的文档。