如何使用FormatStyle协议为.formatted(.percent)指定精度?
问题
需要将进度视图中0到1之间的Double值转换为指定小数位数的格式化字符串,例如将0.789123456转换为"79,1 %"。额外要求是使用Foundation新的FormatStyle协议的.formatted()方法,但尝试多次后无法实现指定精度的需求,以下是尝试的代码:
var progress: Double = 0.789123456 progress.formatted(.percent) // "78,9123456 %" 一开始很简单,但精度不对 progress.formatted(.number.precision(.fractionLength(1))) // "0,79" 只得到小数格式,不是百分比 progress.formatted(.number.precision(.fractionLength(0...1))) // "0,79" 同样不是百分比 progress.formatted(.number.precision(.fractionLength(0...1))).formatted(.percent) // 编译失败 // 错误提示:"Instance method 'formatted' requires the types 'FloatingPointFormatStyle<Double>.FormatOutput' (aka 'String') and 'FloatingPointFormatStyle<Double>.Percent.FormatInput' (aka 'Double') be equivalent" Double(progress.formatted(.number.precision(.fractionLength(1)))) // nil 因为本地化分隔符问题无法转成Double Double("0.79")?.formatted(.percent) // "79 %", 发现是德语Locale的问题! Locale.current // "en_DE (current)" Locale.current.decimalSeparator // "," Double(progress.formatted(.number.precision(.fractionLength(1))).replacingOccurrences(of: Locale.current.decimalSeparator!, with: ".")) // "0,8" Double(progress.formatted(.number.precision(.fractionLength(1))).replacingOccurrences(of: Locale.current.decimalSeparator!, with: "."))?.formatted(.percent) // "80 %" 这种方式太绕,而且精度处理不对
请问是否可以通过FormatStyle实现该需求?还是必须使用旧的NumberFormatter及其maximumFractionDigits属性?
解决方法
完全可以通过FormatStyle协议实现需求,不需要绕弯子或者使用旧的NumberFormatter。你之前的误区是先给数字格式设置精度,再尝试转成百分比,但实际上.percent格式器本身支持直接设置精度参数。
正确的写法如下:
var progress: Double = 0.789123456 // 设置百分比格式,并指定小数位数为1位 let formattedProgress = progress.formatted(.percent.precision(.fractionLength(1))) print(formattedProgress) // 输出 "79,1 %"(对应你的德语Locale)
细节说明:
.percent本身属于FloatingPointFormatStyle的一个变体,支持链式调用.precision()方法来控制小数位数。.fractionLength(1)表示固定保留1位小数,如果你需要设置最小/最大位数范围,可以用.fractionLength(0...1)这类写法。- 该方法会自动适配当前Locale的格式(比如德语的逗号分隔符),不需要手动替换分隔符,也不会出现字符串转Double失败的问题。
如果需要更多自定义格式(比如强制显示正负号、特殊符号等),还可以继续链式调用其他配置方法,比如:
// 强制显示正号,保留1位小数的百分比 progress.formatted(.percent.precision(.fractionLength(1)).sign(strategy: .always))
内容的提问来源于stack exchange,提问作者soundflix
相关产品推荐
相关产品推荐

