扩展Swift中的所有数字类型

时间:2015-07-07 09:47:40

标签: swift

让我说我有这样的事情:

extension NSNumber{
    func toLocalCurrency(fractDigits:Int = 2)->String{
        let formatter = NSNumberFormatter()
        formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
        let userSettings:UserInfo? = UserInfo.first(sortDescriptors: nil, context: AERecord.defaultContext) as? UserInfo
        if let code = userSettings?.currency.name_short {
            formatter.currencyCode = code
        }
        formatter.maximumFractionDigits = fractDigits
        return formatter.stringFromNumber(self)!
    }
    func toLocalCurrencyWithoutFractionDigits()->String{
        return self.toLocalCurrency(fractDigits: 0)
    }
}

我希望尽可能支持大多数swift / mac数字类型,例如。 CGFLoat NSNumber Int Float等。但我不想重复自己(复制粘贴并扩展所有内容)或在我想要使用该功能的任何地方投射。

我尝试扩展像FloatLiteralType / Convertible这样的协议,但还需要强制转换。 “应该”可以以更方便的方式扩展基本类型。

我还想到了全局功能,但它们不易被发现并且感觉更加黑客。

有没有一种很好的方法可以在swift中实现这一目标?

3 个答案:

答案 0 :(得分:9)

正如Sogmeister已经说过你必须使用Swift 2.0来解决你的问题。

然后你可以这样做:

// the solution right now is to implement it twice, I'll explain why
extension IntegerType {

    func toLocalCurrency(fractDigits:Int = 2) -> String {

        let formatter = NSNumberFormatter()
        formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle

        /* ... */

        formatter.maximumFractionDigits = fractDigits
        return formatter.stringFromNumber(self as! NSNumber)! // probably like this
    }

    func toLocalCurrencyWithoutFractionDigits() -> String {

        return self.toLocalCurrency(0)
    }
}

extension FloatingPointType {
    // second implementation goes here
}

// some example
let someUInt = UInt(12340)

someUInt.toLocalCurrency() // returns "12.340,00 €" for me

更新回答:

基本思路是使用函数的默认实现扩展MyProtocol,然后扩展IntegerTypeFloatingPointType。但这不会发生在Swift 2.0(see here)中。它之所以不起作用的原因是here。这是另一个解决方案,它比我的第一个更好。

protocol MyProtocol {}

extension MyProtocol {

    func toLocalCurrency(fractDigits:Int = 2) -> String {

        let formatter = NSNumberFormatter()
        formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle

        /* ... */

        formatter.maximumFractionDigits = fractDigits
        guard let newNumber = self as? NSNumber else { fatalError("this type is not convertable to NSNumber") }
        return formatter.stringFromNumber(newNumber)!
    }

    func toLocalCurrencyWithoutFractionDigits() -> String {

        return self.toLocalCurrency(0)
    }
}

/* extend your number types you need */
extension Int : MyProtocol {} 
extension Double : MyProtocol {} // done

答案 1 :(得分:2)

我们可以创建一个协议,使用默认实现对其进行扩展,并使我们所有的数字类型都符合该协议:

protocol FormattableNumeric {}
extension FormattableNumeric {
    var localized: String {
        guard let number = self as? NSNumber else { return "NaN" }
        return number.description(withLocale: Locale.current)
    }
}
extension Int: FormattableNumeric {}
extension UInt: FormattableNumeric {}
extension Float: FormattableNumeric {}
extension Double: FormattableNumeric {}
// etc.

根据当前的语言环境,您现在可以这样获得格式化的数字:

1000.localized // "1,000"
12_345_678.localized // "12,345,678"
(1_000_000 * Double.pi).localized // "3,141,592.65358979"

当然,为了更好地控制格式,我们还可以在实现中使用NumberFormatter

return NumberFormatter.localizedString(from: number, number: .decimal)

答案 2 :(得分:-1)

详细信息

  • Xcode 10.1(10B61)
  • 迅速4.2

解决方案

extension NSNumber {
    func toLocalCurrency(fractDigits: Int = 2) -> String? {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        formatter.maximumFractionDigits = fractDigits
        return formatter.string(from: self)
    }
    func toLocalCurrencyWithoutFractionDigits() -> String? {
        return toLocalCurrency(fractDigits: 0)
    }
}

extension Numeric {
    func toLocalCurrency(fractDigits: Int = 2) -> String? {
        return (self as? NSNumber)?.toLocalCurrency(fractDigits: fractDigits)
    }
    func toLocalCurrencyWithoutFractionDigits() -> String? {
        return toLocalCurrency(fractDigits: 0)
    }
}

样本

let value = 34.234

func test<T: Numeric>(value: T) {
    let toLocalCurrency = value.toLocalCurrency()
    let result = toLocalCurrency != nil ? "\(toLocalCurrency!)" : "nil"
    print(" type: \(type(of: value)), toLocalCurrency: \(result)")
}

func test<T: NSNumber>(value: T) {
    let toLocalCurrency = value.toLocalCurrency()
    let result = toLocalCurrency != nil ? "\(toLocalCurrency!)" : "nil"
    print(" type: \(type(of: value)), toLocalCurrency: \(result)")
}

test(value: Int8(value))
test(value: Int16(value))
test(value: Int32(value))
test(value: Int(value))
test(value: Float(value))
test(value: Int16(value))
test(value: Int32(value))
test(value: Int8(value))
test(value: Double(value))
test(value: CGFloat(value))
test(value: NSNumber(value: value))

结果

enter image description here