Swift双精度浮点数转换为字符串

143

在我更新了xCode 6之前,将double强制转换为字符串没有任何问题,但现在会出错。

var a: Double = 1.5
var b: String = String(a)

我收到了"doule不可转换为string"的错误信息。是否有其他方法可以实现这个目的?


5
定义var b = "\(a)"这样的语法也许很有用。 - erdekhayser
16个回答

261

它不是类型转换,而是使用格式创建一个字符串值。

let a: Double = 1.5
let b: String = String(format: "%f", a)

print("b: \(b)") // b: 1.500000

以不同的格式呈现:

let c: String = String(format: "%.1f", a)

print("c: \(c)") // c: 1.5
你可以忽略 format 属性,如果不需要格式化。

1
一个小数位更多的双精度浮点数呢?比如让a = 2.34934340320,那么使用let stringValue = String(format: "%f", a) 将会得到2.349343。 - Nico
1
显示器可以通过printf格式选项进行控制,参见:字符串格式说明符printf(3) - zaph
3
您只需更改格式来控制数字的数量:format:"%.1f" = 1位数字 // 1.5format:"%.5f" = 5位数字 // 1.50000 - Megaetron
3
请更新你的回答,在Swift 2.1中,您只需要执行String(yourDouble)即可。 - Alexandre G.
1
你可以使用let代替var。现在不需要多次调用它。 - J A S K I E R
显示剩余2条评论

112
let double = 1.5 
let string = double.description

更新 Xcode 7.1 • Swift 2.1:

现在 Double 类型的数据也可以转换成 String 类型,所以您可以随意使用它:

let double = 1.5
let doubleString = String(double)   // "1.5"

在Swift 3及以上版本中,我们可以扩展LosslessStringConvertible并使其成为泛型

Xcode 11.3 • Swift 5.1或更高版本

extension LosslessStringConvertible { 
    var string: String { .init(self) } 
}

let double = 1.5 
let string = double.string  //  "1.5"

对于固定的小数位数,我们可以扩展FloatingPoint协议:

extension FloatingPoint where Self: CVarArg {
    func fixedFraction(digits: Int) -> String {
        .init(format: "%.*f", digits, self)
    }
}

如果您需要更多地控制数字格式(包括最小和最大小数位数以及舍入模式), 您可以使用NumberFormatter

extension Formatter {
    static let number = NumberFormatter()
}

extension FloatingPoint {
    func fractionDigits(min: Int = 2, max: Int = 2, roundingMode: NumberFormatter.RoundingMode = .halfEven) -> String {
        Formatter.number.minimumFractionDigits = min
        Formatter.number.maximumFractionDigits = max
        Formatter.number.roundingMode = roundingMode
        Formatter.number.numberStyle = .decimal
        return Formatter.number.string(for: self) ?? ""
    }
}

2.12345.fractionDigits()                                    // "2.12"
2.12345.fractionDigits(min: 3, max: 3, roundingMode: .up)   // "2.124"

1
这是黑客行为还是合法的方法?它会在不同的iOS版本中引起任何问题吗? - Esqarrouth
3
不会有与不同的iOS版本相关的问题,同时也适用于OSX。顺便说一下,当使用Double或Int进行字符串插值时,这就是你得到的结果。 - Leo Dabus
非常有用。你不能像%f一样格式化。它也适用于Int,因此您可以为两种类型选择一种方法。 - Patrik Vaberer
这对于0.00001不起作用,它会变成字符串"1e-05"。 - user5005945
String(format: "%.*f", digits, self as! CVarArg) 替换 String(format: "%.\(digits)f", self as! CVarArg) - rmaddy

28

除了@Zaph的回答之外,你还可以在Double上创建一个extension

extension Double {
    func toString() -> String {
        return String(format: "%.1f",self)
    }
}

用法:

var a:Double = 1.5
println("output: \(a.toString())")  // output: 1.5

1
@MaximShoustin,楼主没有足够的声望来投票和回答,需要15个声望。我也不同意创建一个扩展,因为当另一个开发人员看到语句:a.toString()时,肯定会有一个WTF时刻。 - zaph
2
@Zaph 为什么不呢。当然,你可以添加一些前缀并将其更改为 myToString(),以确保它是自定义定义。但是,就像在其他语言中一样,原型设计有助于避免代码重复和良好的维护。 - Maxim Shoustin
@MaximShoustin 新手问题:println("output: \(a.toString())")println("output: \(a)") 有什么区别?第二个选项不会导致编译错误。这个选项是不好的实践吗? - Alex Guerrero
有没有一种聪明的方法来编写一个扩展 Double 或 FloatingPoint 的函数,可以在 Optional Double 上工作并返回一个空字符串? - Kinergy
@Kinergy extension Optional where Wrapped: LosslessStringConvertible { var string: String { guard let unwrapped = self else { return "" } return .init(unwrapped) } } - Leo Dabus

12

Swift 3+:尝试这些代码

let num: Double = 1.5

let str = String(format: "%.2f", num)

10

要在Swift中将任何东西转换为字符串(除了枚举值),只需像在println()方法中一样操作即可。

例如:

var stringOfDBL = "\(myDouble)"

5

这里有很多回答建议使用各种技术。但是在UI中呈现数字时,您必须使用NumberFormatter来使结果得到适当的格式化、舍入和本地化:

let value = 10000.5

let formatter = NumberFormatter()
formatter.numberStyle = .decimal

guard let string = formatter.string(for: value) else { return }
print(string) // 10,000.5

如果您想要固定小数位数,例如针对货币价值。
let value = 10000.5

let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2

guard let string = formatter.string(for: value) else { return }
print(string) // 10,000.50

这种方法的优点在于,它会被正确地本地化,导致在美国显示10,000.50,而在德国显示10.000,50。不同的语言环境对数字有不同的首选格式,我们应该让NumberFormatter根据最终用户的首选格式呈现UI中的数字值。

需要注意的是,虽然在准备UI内的字符串表示时NumberFormatter是必不可少的,但在将数值写入持久性存储、与 Web 服务接口等方面作为字符串时不应使用它。


1
是的,这绝对是正确答案,也是唯一能让本地人感到舒适的答案。 - flymg

3
此函数可让您指定要显示的小数位数:
func doubleToString(number:Double, numberOfDecimalPlaces:Int) -> String {
    return String(format:"%."+numberOfDecimalPlaces.description+"f", number)
}

使用方法:

let numberString = doubleToStringDecimalPlacesWithDouble(number: x, numberOfDecimalPlaces: 2)

使用String(format:"%.*f", numberOfDecimalPlaces, number)替换String(format:"%."+numberOfDecimalPlaces.description+"f", number) - rmaddy

3

Swift 4: 使用以下代码

let number = 2.4
let string = String(format: "%.2f", number)

1
这是与@shiv-kumar提供的解决方案相同的解决方案 https://dev59.com/218e5IYBdhLWcg3w0NCO#46487485 - Eric Aya

2
在Swift 3中:
var a: Double = 1.5
var b: String = String(a)

1
我更倾向于使用NSNumber和NumberFormatter方法(如果需要的话),也可以使用扩展来避免代码臃肿。
extension Double {

   var toString: String {
      return NSNumber(value: self).stringValue
   }

}

你也可以需要反向方法

extension String {

    var toDouble: Double {
        return Double(self) ?? .nan
    }

}

为什么你在返回可选值的同时,如果为 nil 就赋值 .nan?你应该只做其中之一。不要两者都做。顺便问一下,使用 String 初始化器有什么问题吗?你也可以通过扩展 LossLessStringConvertible 协议来使其更通用,而不是扩展 Double。extension LosslessStringConvertible { var string: String { return .init(self) } } - Leo Dabus
你说得对,返回Double?是无意义的,因为我已经检查过它是否为空并返回NaN。 - Giuseppe Mazzilli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接