// SI units
enum Magnitude : Measurement {
case Milli = Measurement(-3, \"ml\")
case Centi = Measurement(-2, \"cl\")
case Desi = Measurement(-1, \"dl\")
Depending on what you need, maybe you can combine an enumeration of SI unit scales and the example in the Computed Properties section of Apple Swift Programming Guide. In this simplistic scheme all of input measurements would be stored in the same units (grams in this example). Then you would convert to whatever units you needed in the output.
It is very readable.
enum SI {
case kg
case hg
case dag
case g
case dg
case cg
case mg
var scale: Double {
switch self {
case kg: return 0.001
case hg: return 0.01
case dag: return 0.1
case g: return 1.0
case dg: return 10.0
case cg: return 100.0
case mg: return 1000.0
}
}
}
extension Double {
var kg: Double {return self * 1000.0}
var hg: Double {return self * 100.0}
var dag: Double {return self * 10.0}
var g: Double {return self}
var dg: Double {return self * 0.1}
var cg: Double {return self * 0.01}
var mg: Double {return self * 0.001}
func convertTo(si: SI) -> Double {return self * si.scale}
}
Example:

Did you consider using a dictionary? For example:
let magnitudes: [String: Double] = [
"ml": -3,
"cl": -2,
"dl": -1,
"g": 0,
"kg": 3
]
// list all units:
println(", ".join(magnitudes.keys)) // kg, g, ml, cl, dl
// convert
func convert(from: String, to: String, value: Double) -> Double{
let mag1 = __exp10(magnitudes[from]!)
let mag2 = __exp10(magnitudes[to]!)
return value * mag1 / mag2
}
let result = convert("dl", "ml", 3.0)
println(result) // 300.0
If you want to be able to specify the unit of the mass with a String perhaps you could use String to represent the shorthand name and variables to give you more information about the unit, such as magnitude. Here's an example:
1. MassUnit
enum MassUnit: String {
case Milligrams = "mg"
case Grams = "g"
case Kilos = "kg"
case Tons = "t"
var magnitude: Int {
let mag: Int
switch self {
case .Milligrams: mag = -3
case .Grams : mag = 0
case .Kilos : mag = 3
case .Tons : mag = 6
}
return mag
}
static func ordersOfMagnitudeFrom(unit1: MassUnit, to unit2: MassUnit) -> Int {
return unit1.magnitude - unit2.magnitude
}
}
extension MassUnit: Printable {
var description: String {
return self.rawValue
}
}
2. Then, for storing actual masses you could use a Struct, which could also handle the conversions. For example:
struct Mass {
var value : Double
var unit : MassUnit
static func convertMass(mass: Mass, toUnit unit: MassUnit) -> Mass {
let ordersOfMagnitude = MassUnit.ordersOfMagnitudeFrom(mass.unit, to: unit)
let multipler = pow(10.0, Double(ordersOfMagnitude))
return Mass(value: mass.value * multipler, unit: unit)
}
// Returns an optional Mass because we can't know for sure
// unitString will represent a MassUnit.
static func convertMass(mass: Mass, toUnit unitString: String) -> Mass? {
if let unit = MassUnit(rawValue: unitString) {
return convertMass(mass, toUnit: unit)
}
return nil
}
}
extension Mass {
init?(value: Double, _ unitString: String) {
if let unit = MassUnit(rawValue: unitString) {
self = Mass(value: value, unit: unit)
} else {
return nil
}
}
}
extension Mass : Printable {
var description: String {
return "\(value) \(unit)"
}
}
3. Then you can use the masses and units:
if let mass = Mass(value: 1, "kg"),
let convertedMass = Mass.convertMass(mass, toUnit: "g") {
println("\(mass) converted to \(MassUnit.Grams) equals \(convertedMass)")
// Prints: 1.0 kg converted to g equals 1000.0 g
}
However if you use a unitString that isn't convertible to a MassUnit (either when creating or converting) nil will be returned. For example:
let mass = Mass(value: 1, "NotAUnit") // nil