Mastering macOS Programming
上QQ阅读APP看书,第一时间看更新

Creating multiple distinct types from a single type

The flipside of that principle is a situation in which we pass values of the same type, but which may have different meanings. A method may need to accept both inches and centimeters as Double, but will need to know which it is dealing with. We could add a second argument, a Bool that states whether or not the argument is in inches; but what about if there is also the need to accept millimeters? Or even lightyears?

This problem can also occur in compound data types; coordinates, for example, can be Cartesian or polar, but both would be expressed as a combination of two Double values.

Well, once again, there is a way. We can define an enum that consists of different cases wrapping the same type of data:

enum Coordinate 
{
case cartesian(x: Double, y: Double)
case polar(r: Double, theta: Double)
}

So. we have created a type, Coordinate, which groups together two distinct cases that just happen to have the same associated value type.

Nevertheless, Coordinate.cartesian and Coordinate.polar are different types as far as the compiler's type-checking is concerned.

Let's see this in action:

let myCartesianPosition = Coordinate.cartesian(x: 100.0, y: 100.0) 
let myPolarPosition = Coordinate.polar(r: 50.0, theta: 0.5)

var myCoordinates: [Coordinate] = []
myCoordinates.append(myCartesianPosition)
myCoordinates.append(myPolarPosition)

for coordinate in myCoordinates
{
switch coordinate
{
case .cartesian(let c):
// do something with Cartesian coordinate
print("Cartesian coordinate: x = \(c.x), y = \(c.y)")
case .polar(let p):
// do something with polar coordinate
print("Polar coordinate: r = \(p.r), theta = \(p.theta)")
}
}

This is a useful technique, and is worth experimenting with.