如何为所有Measurement Unit创建通用自定义FormatStyle?
通用保留原单位的Measurement格式化方案
问题背景
我有多个测量单位(如UnitLength、UnitDuration、UnitSpeed等),多数情况下需要使用保留原单位的格式化器(formatter.unitOptions = .providedUnit)。
为简化调用,我为长度单位创建了自定义FormatStyle,代码如下:
struct ProvidedUnitFormatStyle: FormatStyle { func format(_ measurement: Measurement<UnitLength>) -> String { let formatter = MeasurementFormatter() formatter.unitOptions = .providedUnit return formatter.string(from: measurement) } } extension FormatStyle where Self == ProvidedUnitFormatStyle { static var providedUnit: ProvidedUnitFormatStyle { .init() } } // usage: distance.formatted(.providedUnit)
但如果要为UnitDuration实现同样功能,就得重复编写代码。
我尝试在func format()中使用Measurement<Dimension>,期望适配所有单位,但编译器报错:
Instance method 'formatted' requires the types
Measurement<Dimension>andMeasurement<UnitDuration>be equivalent
有没有办法无需为每个Unit重复代码就能实现该功能?
解决方案
可以通过泛型FormatStyle或者扩展Measurement类型两种方式实现通用化,避免重复代码:
方式一:泛型FormatStyle
定义带泛型约束的FormatStyle结构体,约束其处理的Measurement单位必须是Dimension子类,适配所有测量单位:
struct ProvidedUnitFormatStyle<Unit: Dimension>: FormatStyle { func format(_ measurement: Measurement<Unit>) -> String { let formatter = MeasurementFormatter() formatter.unitOptions = .providedUnit return formatter.string(from: measurement) } } // 为常用单位添加简洁的静态调用入口 extension FormatStyle where Self == ProvidedUnitFormatStyle<UnitLength> { static var providedUnitLength: ProvidedUnitFormatStyle<UnitLength> { .init() } } extension FormatStyle where Self == ProvidedUnitFormatStyle<UnitDuration> { static var providedUnitDuration: ProvidedUnitFormatStyle<UnitDuration> { .init() } } extension FormatStyle where Self == ProvidedUnitFormatStyle<UnitSpeed> { static var providedUnitSpeed: ProvidedUnitFormatStyle<UnitSpeed> { .init() } }
用法示例:
let distance = Measurement(value: 100, unit: UnitLength.meters) print(distance.formatted(.providedUnitLength)) // 输出 "100 m" let time = Measurement(value: 30, unit: UnitDuration.seconds) print(time.formatted(.providedUnitDuration)) // 输出 "30 s"
方式二:直接扩展Measurement类型
这种方式更简洁,无需单独定义FormatStyle,直接给所有Dimension子类的Measurement添加格式化方法:
extension Measurement where UnitType: Dimension { func formatted(with unitOption: MeasurementFormatter.UnitOptions = .providedUnit) -> String { let formatter = MeasurementFormatter() formatter.unitOptions = unitOption return formatter.string(from: self) } }
用法示例:
let speed = Measurement(value: 60, unit: UnitSpeed.kilometersPerHour) print(speed.formatted()) // 默认使用.providedUnit,输出 "60 km/h" // 也可灵活指定其他单位选项 print(speed.formatted(with: .naturalScale))
内容的提问来源于stack exchange,提问作者phi
相关产品推荐
相关产品推荐

