You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为所有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> and Measurement<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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 09:25:24