Reputation: 815
Swift implements the Measurement
type which can be used to hold values such as speeds, altitudes, etc. in their desired metric.
For example:
// 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
However, even though UnitLength
and UnitSpeed
are both subclasses of Unit
, measurements using these types can not be passed in polymorphically into a function in swift.
For example, the following function does not work if you pass in an object of type Measurement<UnitLength>
or Measurement<UnitSpeed>
.
func formatMeasurementAsString(measurement: Measurement<Unit>) -> String {
return "\(Int(measurement.value)) \(measurement.unit.symbol)"
}
Passing in either speed
or altitude
defined above into this function yields the following error: Cannot convert value of type 'Measurement<UnitSpeed>' to expected argument type 'Measurement<Unit>'
EDIT:
So you can explicitly type both speed
and altitude
in this example as type Measurement<Unit>
. However, if you do this, they lose the incredibly useful .convert(to:)
function unless you typecast them back into Measurement<UnitLength>
before converting, which is not very helpful.
Upvotes: 3
Views: 321
Reputation: 51993
You can make the function generic
func formatMeasurementAsString<T: Unit>(measurement: Measurement<T>) -> String {
return "\(Int(measurement.value)) \(measurement.unit.symbol)"
}
Example
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 m
60 km/h
Upvotes: 6