Enums and Associated Values
Swift's enum goes far beyond a list of named constants, letting each case carry its own data.
読了時間 2 分
An enum defines a type with a fixed set of possible values, called cases. That much is familiar from other languages — but Swift's enums can also attach data to each case, making them one of the language's most powerful tools for modeling real-world states.
A basic enum
enum Direction {
case north, south, east, west
}
let heading = Direction.north
switch heading {
case .north:
print("Heading north")
case .south:
print("Heading south")
case .east, .west:
print("Heading east or west")
}Once the type is known (as it is here, via Direction.north), you can drop the type name at the call site and just write .north — Swift infers it from context, which is why the switch cases above only need the leading dot.
Because a switch over an enum must be exhaustive, adding a new case later (say, .northeast) causes every existing switch on that enum to fail to compile until you handle the new case — turning a class of "forgot to update this" bugs into an immediate compiler error.
Associated values: attaching data to a case
This is the feature that sets Swift's enums apart. Each case can carry its own values, of different types per case:
enum NetworkResult {
case success(data: String)
case failure(errorCode: Int, message: String)
case loading
}
func handle(_ result: NetworkResult) {
switch result {
case .success(let data):
print("Got data: \(data)")
case .failure(let code, let message):
print("Error \(code): \(message)")
case .loading:
print("Still loading...")
}
}
handle(.success(data: "user profile"))
handle(.failure(errorCode: 404, message: "Not found"))A single NetworkResult value is exactly one of these three cases at a time, each carrying exactly the data relevant to it — .success doesn't need an error code, and .failure doesn't need response data. Modeling this with a struct and a bunch of optional properties (data: String?, errorCode: Int?) would allow invalid combinations, like a "success" that also has an error code. The enum makes that combination impossible to construct in the first place.
Enums with raw values
A separate feature — raw values — gives every case a fixed underlying value of the same type, useful when you need to map to and from something like a string or number:
enum HTTPStatus: Int {
case ok = 200
case notFound = 404
case serverError = 500
}
let status = HTTPStatus.notFound
print(status.rawValue) // 404
let fromCode = HTTPStatus(rawValue: 200) // Optional(.ok) — init can fail, so it's optionalRaw values and associated values solve different problems: raw values give a fixed, simple mapping (useful for things like status codes), while associated values let each case carry differently-shaped, dynamic data. Many real Swift codebases use both patterns extensively — recognizing which one a given enum needs is a skill worth building early.