Swift 3 十进制、NSDecimal 和 NSDecimalNumber

Posted

技术标签:

【中文标题】Swift 3 十进制、NSDecimal 和 NSDecimalNumber【英文标题】:Swift 3 Decimal, NSDecimal and NSDecimalNumber 【发布时间】:2016-12-14 17:36:59 【问题描述】:

我正在尝试将 NumberFormatter 与 Swift 3 Decimal 一起使用,但我对 Decimal 的实际实现方式感到困惑。我遇到的问题是Decimal 是一个结构,所以每次我想使用格式化程序时,我都必须将它桥接到NSDecimalNumber,我想避免这种情况。

let formatter = NumberFormatter()
formatter.numberStyle = .decimal
let decimal = Decimal(integerLiteral: 3)
let string = formatter.string(from: decimal as NSDecimalNumber)

实现我自己的采用Decimal 的扩展是理想的解决方法吗?

extension NumberFormatter 
    open func string(from number: Decimal) -> String? 
        return string(from: number as NSDecimalNumber)
    

更一般地说,每次我需要传入一个对象类型时,我是否需要桥接Decimal 或编写更多扩展?

编辑

我想我更普遍地想知道 Swift 3 中的 NSDecimal DecimalNSDecimalNumber。我完全不清楚这里发生了什么。对于 Swift 3,我应该用 Decimal 替换 NSDecimalNumber 吗?文档写道:

Foundation 框架的 Swift 覆盖提供了 Decimal 结构,它连接到 NSDecimalNumber 类。 Decimal 值类型提供与 NSDecimalNumber 引用类型相同的功能,并且两者可以在与 Objective-C API 交互的 Swift 代码中互换使用。这种行为类似于 Swift 如何将标准字符串、数字和集合类型桥接到它们相应的 Foundation 类。

起初我以为Decimal 是新的NSDecimalNumber,就像Error 是新的NSError - 但现在我不太确定了。这还说“十进制值类型提供与 NSDecimalNumber 引用类型相同的功能”——这真的是真的吗?我似乎无法获得很多相同的功能(当然,如果不先桥接它,这就是他们的意思吗?)。我在这里和那里找到了一些帖子和一些信息,但没有什么令人信服的。有没有人有任何知识或见解?

我的应用专门使用 NSDecimalNumber 进行货币和格式设置,因此舍入和格式设置是一个高优先级。

【问题讨论】:

据我所见,NumberFormatter(style: .decimal) 不会编译,而且NumberFormatter() 不会创建一个可选项。 – 这是你的真实代码,还是我忽略了什么? extension NumberFormatter convenience init(style: NumberFormatter.Style) self.init() self.numberStyle = style func string(from decimal: Decimal) -> String? return string(from: decimal as NSNumber) 是的,这是我的真实代码,它编译得很好。我在 Xcode 8.1 上,这在 8.2 中是否发生了变化? 在 Xcode 8.1 中无法为我编译,因为没有这样的初始化程序。 对不起,我们有一个简单的 NSNumberFormatter 扩展,代码已经更新 【参考方案1】:

我在 swift-users 板上提出了我的问题并得到了很好的答案,请在此处查看:https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20161219/004220.html

响应的文本版本:

Swift 3 引入了 Decimal 类,起初我认为它应该在 Swift 中“替换” NSDecimalNumber,例如 Error 是新的 NSError 等。但是,经过进一步调查,我不清楚这实际上是这样的。看起来 Swift 3 的 Decimal 更像是一个 NSDecimal,但有一些桥接,因此它可以在需要时使用 NSDecimalNumber 的方法。我想知道的是,我应该用十进制替换我的应用程序中的 NSDecimalNumber 吗? Decimal 是 Swift 中 NSDecimalNumber 的继承者吗?

Decimal 实际上是一个结构体,而不是一个类,实际上它只是 Objective-C 中NSDecimal 结构体的 Swift 名称。在 Swift 中,NSDecimalAdd 之类的函数作为Decimal 上的运算符公开,用于满足SignedNumber 等各种数字协议的要求。

最终结果是Decimal 很像IntDouble——它是一种可以方便地用于进行各种数学运算的值类型。那么NSDecimalNumber 就等价于NSNumber

由于我的应用程序正在进行大量格式化,因此需要在 Decimal 和 NSDecimalNumber 之间进行大量转换,或者添加要使用的扩展名,所以我认为如果没有很多扩展名,这将是不自然/方便的。 Swift 是否计划改进 Decimal 使其更适用于 NumberFormatter 或其他面向对象的数字 API?希望我已经提供了足够的信息来回答我的问题。

使用NSDecimalNumber 的Objective-C API 应该桥接到Decimal,就像NSString 桥接到String 一样。但是,这种桥接可能不适用于类别方法;你可以通过在Decimal 上编写一个扩展来将它们暴露给 Swift,它将self 转换为NSDecimalNumber,然后调用你的 Objective-C 方法。

同样,您应该能够通过将DecimalNumberFormatter 一起使用,通过转换为NSDecimalNumber,就像您将IntDouble 转换为NSNumber 以将它们与NumberFormatter 一起使用。

【讨论】:

使用它比Double类型有什么优势? @brahimm 你永远不应该使用 Double/Float 来表示货币。你可以在这里阅读一个很好的解释:***.com/questions/3730019/… @Caio 我也有同样的担忧,但我现在也担心 Swift 的 Decimal 没有解决这个问题:/

以上是关于Swift 3 十进制、NSDecimal 和 NSDecimalNumber的主要内容,如果未能解决你的问题,请参考以下文章

如何声明 NSDecimal 以及如何使用 NSDecimalAdd

NSDecimal、NSDecimalNumber、CFNumber 之间的正确选择是啥?

NSDecimal 需要桥接

从 `NSDecimal` 或 `NSDecimalNumber` 转换为 C# 的 `decimal` 类型

NSDecimalNumber 用于 Swift 中的货币精度 [重复]

将非常大的 NSDecimal 转换为字符串,例如。 400,000,000,000 -> 400 T 等等