Reputation: 551
I need a function that works with the value in any Measurement in Swift 3. Below is an example:
var test2 = Measurement<UnitEnergy>( value: 10.1234, unit: .calories)
func printMeasurementGeneric( measurement: Measurement<Unit>) {
print( measurement.value)
}
func printMeasurementEnergy( measurement: Measurement<UnitEnergy>) {
print( measurement.value)
}
printMeasurementEnergy(measurement: test2) // This works
printMeasurementGeneric(measurement: test2) // This doesn't work and give the following error
Playground execution failed: error: Measurement Playground.playground:136:38: error: cannot convert value of type 'Measurement<UnitEnergy>' to expected argument type 'Measurement<Unit>'
printMeasurementGeneric(measurement: test2)
What does the function need to look like for PrintMeasurementGeneric for this to work?
I've made some progress and now have the following code in Swift playground
var test = Measurement<UnitEnergy>( value: 10.1234, unit: .calories)
func printMeasurementGeneric<A:Dimension>( measurement: Measurement<A>) {
print( measurement.value)
}
// This works
printMeasurementGeneric(measurement: test) // This works
// The following doesn't work
var objectValue: Any?
objectValue = test
var meas = objectValue as! Measurement<Dimension> // Could not cast value of type 'Foundation.Measurement<NSUnitEnergy>' (0x11d324028) to 'Foundation.Measurement<NSDimension>' (0x11d324088).
printMeasurementGeneric(measurement: meas)
I'm trying to use the objectValue in an NSControl to hold the Measurement. How do I do this within checking if it can be cast to every measurement type?
Some more work and including edits from below. Not a pretty or robust solution.
var test = Measurement<UnitEnergy>( value: 10.1234, unit: .calories)
func printMeasurementGeneric<A>( measurement: Measurement<A>) {
print( measurement.value)
}
// This works
printMeasurementGeneric(measurement: test) // This works
// The following works but isn't pretty. Is there a better way
var objectValue: Any?
objectValue = test
if objectValue is Measurement<UnitFrequency> {
let meas = objectValue as! Measurement<UnitFrequency>
printMeasurementGeneric(measurement: meas)
} else if objectValue is Measurement<UnitLength> {
let meas = objectValue as! Measurement<UnitLength>
printMeasurementGeneric(measurement: meas)
} else if objectValue is Measurement<UnitSpeed> {
let meas = objectValue as! Measurement<UnitSpeed>
printMeasurementGeneric(measurement: meas)
} else if objectValue is Measurement<UnitEnergy> {
let meas = objectValue as! Measurement<UnitEnergy>
printMeasurementGeneric(measurement: meas)
} else {
print("Didn't find cast!")
}
Upvotes: 1
Views: 257
Reputation: 7756
This can be accomplished with a protocol:
protocol HasValue {
var value: Double { get set }
}
extension Measurement: HasValue { }
func printValue<T: HasValue>(of item: T) {
print(item.value) // prints "10.1234"
}
var test = Measurement<UnitEnergy>( value: 10.1234, unit: .calories)
printValue(of: test)
Any function similar to printValue should be able to use any measurement generically. You could include the functions in a protocol extension for organization.
Upvotes: 0
Reputation: 3440
Change your PrintMeasurementGeneric
function to this.
func PrintMeasurementGeneric<Dimension>( measurement: Measurement<Dimension>) {
print( measurement.value)
}
I used the Dimension
type instead of Unit
. Either should work but all of the measurement types conform to Dimension
(an abstract subclass of Unit
).
Hamish (below) is right.
Upvotes: 2