使 NSDecimalNumber 可编码
Making NSDecimalNumber Codable
是否可以扩展 NSDecimalNumber
以符合 Encodable & Decodable
协议?
在 swift 中你应该使用 Decimal 类型。此类型确认协议 Encodable & Decodable
开箱即用。
如果您有 NSDecimalNumber
类型的代码,很容易将其转换为 Decimal
let objcDecimal = NSDecimalNumber(decimal: 10)
let swiftDecimal = (objcDecimal as Decimal)
无法扩展 NSDecimalNumber
以符合 Encodable
和 Decodable
协议。 Jordan Rose 解释如下 swift evolution email thread.
如果你需要 NSDecimalValue
输入你的 API 你可以在 Decimal
.
周围构建计算 属性
struct YourType: Codable {
var decimalNumber: NSDecimalNumber {
get { return NSDecimalNumber(decimal: decimalValue) }
set { decimalValue = newValue.decimalValue }
}
private var decimalValue: Decimal
}
顺便说一句。如果您使用 NSNumberFormatter
进行解析,请注意 known bug 在某些情况下会导致精度损失。
let f = NumberFormatter()
f.generatesDecimalNumbers = true
f.locale = Locale(identifier: "en_US_POSIX")
let z = f.number(from: "8.3")!
// z.decimalValue._exponent is not -1
// z.decimalValue._mantissa is not (83, 0, 0, 0, 0, 0, 0, 0)
以这种方式解析字符串:
NSDecimalNumber(string: "8.3", locale: Locale(identifier: "en_US_POSIX"))
使用 Swift 5.1 您可以使用 属性 包装器来避免编写自定义 init(from decoder: Decoder)
/ encode(to encoder: Encoder)
的样板.
@propertyWrapper
struct NumberString {
private let value: String
var wrappedValue: NSDecimalNumber
init(wrappedValue: NSDecimalNumber) {
self.wrappedValue = wrappedValue
value = wrappedValue.stringValue
}
}
extension NumberString: Decodable {
init(from decoder: Decoder) throws {
value = try String(from: decoder)
wrappedValue = NSDecimalNumber(string: value)
}
}
extension NumberString: Encodable {
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(wrappedValue.stringValue)
}
}
extension NumberString: Equatable {}
用法:
struct Foo: Codable {
@NumberString var value: NSDecimalNumber
}
是否可以扩展 NSDecimalNumber
以符合 Encodable & Decodable
协议?
在 swift 中你应该使用 Decimal 类型。此类型确认协议 Encodable & Decodable
开箱即用。
如果您有 NSDecimalNumber
类型的代码,很容易将其转换为 Decimal
let objcDecimal = NSDecimalNumber(decimal: 10)
let swiftDecimal = (objcDecimal as Decimal)
无法扩展 NSDecimalNumber
以符合 Encodable
和 Decodable
协议。 Jordan Rose 解释如下 swift evolution email thread.
如果你需要 NSDecimalValue
输入你的 API 你可以在 Decimal
.
struct YourType: Codable {
var decimalNumber: NSDecimalNumber {
get { return NSDecimalNumber(decimal: decimalValue) }
set { decimalValue = newValue.decimalValue }
}
private var decimalValue: Decimal
}
顺便说一句。如果您使用 NSNumberFormatter
进行解析,请注意 known bug 在某些情况下会导致精度损失。
let f = NumberFormatter()
f.generatesDecimalNumbers = true
f.locale = Locale(identifier: "en_US_POSIX")
let z = f.number(from: "8.3")!
// z.decimalValue._exponent is not -1
// z.decimalValue._mantissa is not (83, 0, 0, 0, 0, 0, 0, 0)
以这种方式解析字符串:
NSDecimalNumber(string: "8.3", locale: Locale(identifier: "en_US_POSIX"))
使用 Swift 5.1 您可以使用 属性 包装器来避免编写自定义 init(from decoder: Decoder)
/ encode(to encoder: Encoder)
的样板.
@propertyWrapper
struct NumberString {
private let value: String
var wrappedValue: NSDecimalNumber
init(wrappedValue: NSDecimalNumber) {
self.wrappedValue = wrappedValue
value = wrappedValue.stringValue
}
}
extension NumberString: Decodable {
init(from decoder: Decoder) throws {
value = try String(from: decoder)
wrappedValue = NSDecimalNumber(string: value)
}
}
extension NumberString: Encodable {
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(wrappedValue.stringValue)
}
}
extension NumberString: Equatable {}
用法:
struct Foo: Codable {
@NumberString var value: NSDecimalNumber
}