接受任何类型的测量单位的Swift函数

3

Swift 实现了 Measurement 类型,可用于以所需的度量单位保存速度、高度等值。

例如:

// Going to explicitly type here so the question is clear

var speed: Measurement<UnitSpeed> = Measurement(value: 10, unit: UnitSpeed.metersPerSecond)
var altitude: Measurement<UnitLength> = Measurement(value: 500, unit: UnitLength.meters)

altitude.convert(to: UnitLength.feet)

print("500 meters is roughly \(Int(altitude.value)) feet")
// Prints: 500 meters is roughly 1640 feet

然而,尽管UnitLengthUnitSpeed都是Unit的子类,但在Swift中无法将使用这些类型的测量值多态地传递给函数。例如,如果你传入Measurement<UnitLength>Measurement<UnitSpeed>类型的对象,则以下函数不起作用。
func formatMeasurementAsString(measurement: Measurement<Unit>) -> String {
    return "\(Int(measurement.value)) \(measurement.unit.symbol)"
}

将上述代码中定义的speedaltitude传入此函数会产生以下错误:无法将类型为“Measurement<UnitSpeed>”的值转换为预期参数类型“Measurement<Unit>”

编辑:

因此,在此示例中,您可以显式地将speedaltitude都指定为类型Measurement<Unit>。但是,如果这样做,则它们将失去非常有用的.convert(to:)函数,除非在转换之前将它们强制转型回Measurement<UnitLength>,否则不太有帮助。


3
知道这个可能解决不了你的问题,但我要告诉你,像 formatMeasurementAsString 这样的函数会削弱使用 Measurement 带来的99% 的好处,也就是使用 MeasurementFormatter - Alexander
谢谢@Alexander-ReinstateMonica,我会研究一下! - IanTimmis
1
只是提醒一下,编写代码时要非常小心,不要无意中将格式化的假设编码到代码中。在这种情况下,您正在编码一个假设,即单位应该以阿拉伯数字打印,并用每3个数字分组的逗号隔开,然后是一个空格,接着是单位的英文名称。这在世界上大多数地区都是错误的。MeasurementFormatter实现了所有微妙和复杂的本地化逻辑,为您正确处理此问题。 - Alexander
1个回答

6
您可以使函数具有通用性。
func formatMeasurementAsString<T: Unit>(measurement: Measurement<T>) -> String {
    return "\(Int(measurement.value)) \(measurement.unit.symbol)"
}

示例

let length = Measurement(value: 180.0, unit: UnitLength.meters)
let speed = Measurement(value: 60, unit: UnitSpeed.kilometersPerHour)

print(formatMeasurementAsString(measurement: length))
print(formatMeasurementAsString(measurement: speed))

180米
时速60公里


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