1. Enumeration Syntax πŸ‘©β€πŸ’»

1. Enumerations in Swift

Enumeration은 μ—°κ΄€λœ 값듀을 곡톡 νƒ€μž…μœΌλ‘œ κ·Έλ£Ήν™”ν•΄ Type-Safeν•œ μ½”λ“œλ₯Ό μž‘μ„±ν•˜λ„λ‘ λ•λŠ”λ‹€.
Swift μ—μ„œ Enumeration 은 주어진 값이 String, Character, Interger, Float μ–΄λ–€ 것이든 μ €μž₯ν•  수 μžˆλ‹€. λ‹€λ₯Έ ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄μ—μ„œ unions λ˜λŠ” variants κ°€ μž‘λ™ν•˜λŠ” 것과 κ°™λ‹€.

Swift μ—μ„œ Enumeration 은 κ·Έ 자체둜 First-Class Types 둜 μ „ν†΅μ μœΌλ‘œ Classes μ—μ„œλ§Œ μ œκ³΅λ˜λŠ” λ§Žμ€ κΈ°λŠ₯을 μ±„νƒν•œλ‹€.

  • Initializers
  • Computed Properties
  • Instance methods
  • Extend their original implementation
  • Confirm to protocols


Syntax

enum SomeEnumeration {
    case one
    case two
    case three
}
enum SomeEnumeration {
    case one, two, three
}
  1. Enumeration 은 μƒˆ Type을 λ§Œλ“€μ–΄ λ‚Έλ‹€. λ”°λΌμ„œ Swift 의 λ‹€λ₯Έ Types 와 λ§ˆμ°¬κ°€μ§€λ‘œ 이름은 λŒ€λ¬Έμžλ‘œ μ‹œμž‘ν•œλ‹€.
  2. Enumeration 은 Singleton을 기반으둜 ν•˜λ―€λ‘œ 이름 μ—­μ‹œ 자λͺ…ν•˜κ²Œ μ½νžˆλ„λ‘ λ³΅μˆ˜ν˜•(plural)이 μ•„λ‹Œ λ‹¨μˆ˜ν˜•(singular)을 μ‚¬μš©ν•œλ‹€.

2. Enumeration Examples

enum CompassPoint {
    case north
    case south
    case east
    case west
}

Swift 의 Enumeration 은 λ‹€λ₯Έ 언어와 달리 μ•”μ‹œμ μœΌλ‘œ integer value(0, 1, 2, …)λ₯Ό ν• λ‹Ήν•˜μ§€ μ•ŠλŠ”λ‹€. caseλŠ” μ˜¨μ „νžˆ 자기 μžμ‹ μ„ κ°’μœΌλ‘œ κ°–λŠ”λ‹€.


각 case λŠ” λ‹€μŒκ³Ό 같이 ,λ₯Ό μ΄μš©ν•΄ ν•œ μ€„λ‘œ 적을 수 μžˆλ‹€.

enum Planet {
    case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}

μœ„μ—μ„œ μ •μ˜ν•œ CompassPoint, Planet은 각각 ν•˜λ‚˜μ˜ Type 을 λ§Œλ“€μ–΄λƒˆμœΌλ©°, λ‘˜μ€ μ„œλ‘œ λ‹€λ₯Έ Type 이닀.

var directionToHead = CompassPoint.west
print("Type of directionToHead is '\(type(of: directionToHead))'")


이미 Type 이 정해진 경우, Dot Syntax(.)λ₯Ό μ΄μš©ν•  수 μžˆλ‹€.

var directionToHead = CompassPoint.west
print("directionToHead is '\(directionToHead)'")  // directionToHead is west

directionToHead = .east
print("directionToHead is '\(directionToHead)'")  // directionToHead is east

var anotherDirectionToHead: CompassPoint
anotherDirectionToHead = .south
print("anotherDirectionToHead is '\(anotherDirectionToHead)'")    // anotherDirectionToHead is south

2. Matching Enumeration Values with Switch πŸ‘©β€πŸ’»

1. Matching with Switch

Enumeration 은 Switchλ₯Ό μ΄μš©ν•΄ λ‹€μŒκ³Ό 같이 λ§€μΉ­μ‹œν‚¬ 수 μžˆλ‹€.

enum CompassPoint {
    case east, west, south, north
}

var directionToHead: CompassPoint
directionToHead = .south

switch directionToHead {
case .north:
    print("Lots of planets have a north")
case .south:
    print("Watch out for penguins")
case .east:
    print("Where the sun rises")
case .west:
    print("Where the skies are blue")
}
Watch out for penguins

2. Switch must be exhaustive

directionToHead = .south

switch directionToHead {    // Switch must be exhaustive - add missing case: '.north'
case .south:
    print("Watch out for penguins")
}

south λ₯Ό μ œμ™Έν•œ case λ₯Ό μ œκ±°ν–ˆλ‹€. directionToHead λŠ” ν˜„μž¬ south λ‹ˆκΉŒ 문제 없을 것 κ°™μ§€λ§Œ, Swift λŠ” 이 Switchκ°€ μ™„μ „ν•˜μ§€ μ•Šμ€ 것을 λ°œκ²¬ν•˜κ³  compile-errorλ₯Ό λ°œμƒμ‹œν‚¨λ‹€.
λ”°λΌμ„œ, μ‚¬μš©λ˜μ§€ μ•Šλ”λΌλ„ λ‹€μŒκ³Ό 같이 case miss-matching이 μΌμ–΄λ‚˜μ§€ μ•Šλ„λ‘ λ‹€μŒκ³Ό 같이 μ²˜λ¦¬ν•΄μ•Όν•œλ‹€.

switch directionToHead {
case .south:
    print("Watch out for penguins")
default:
    print("This direction is not south")
}

Switchκ°€ Enumeration을 λ‹€λ£° λ•Œ caseλŠ” μ™„μ „ν•΄μ•Ό(exhaustive)ν•œλ‹€.


3. Iterating over Enumeration Cases πŸ‘©β€πŸ’»

Enumeration 에 CaseIterable ν”„λ‘œν† μ½œμ„ μ±„νƒν•¨μœΌλ‘œμ¨ ν•΄λ‹Ή Enum Type 의 λͺ¨λ“  cases λ₯Ό κ°–λŠ” Collection을 μƒμ„±ν•œλ‹€.

Syntax

enum SomeEnumeration: CaseIterable {
    case one, two, three
}


enum Beverage: CaseIterable {
    case coffee, tea, juice
}
let numberOfChoices = Beverage.allCases.count

print("\(numberOfChoices) beverages available\n")

for beverage in Beverage.allCases {
    print(beverage)
}
3 beverages available

coffee
tea
juice

4. Associated Values πŸ‘©β€πŸ’»

λ•Œλ‘œλŠ” Enumeration 의 cases κ°€ 자기 μžμ‹ μ˜ κ°’ 외에 λ‹€λ₯Έ νƒ€μž…μ˜ 값을 ν•¨κ»˜ μ €μž₯ν•˜λŠ” 것이 μœ μš©ν•  λ•Œκ°€ μžˆλ‹€. 이λ₯Ό Associated Value라고 ν•˜λ©°, μ΄λŠ” λ‹€λ₯Έ ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄μ—μ„œ unions, tagged unions, variants 둜 μ•Œλ €μ§„ 것듀과 μœ μ‚¬ν•˜λ‹€.

Syntax

enum SomeEnumeration {
    case one(Int)
    case two(Int, Int)
    case three(String)
}

1. Barcode Systems for Examples

1D barcodes in UPC format, 2D barcodes in QR code format λ₯Ό μ΄μš©ν•΄ μ„€λͺ…ν•œλ‹€.

  • Barcodes UPC

Barcodes UPC

  • Barcodes QR code

Barcodes QE code


μš°μ„  UPC λŠ” 1D λ°”μ½”λ“œλ‘œ numebr system, manufacturer code, product code, check 순으둜 이뀄진 4개의 Int 그룹으둜 κ΅¬μ„±λ˜μ–΄μ§„λ‹€.
λ‹€μŒμœΌλ‘œ QR code λŠ” 2D λ°”μ½”λ“œλ‘œ 2,953자 μ΄λ‚΄μ˜ μ–΄λ– ν•œ ISO 8859-1 λ¬Έμžλ“  μ €μž₯ν•  수 μžˆλ‹€.

2. Adopt Associated Values

enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
}

Barcode enum type 이 κ°€μ§ˆ 수 μžˆλŠ” 값은 λ‹€μŒκ³Ό κ°™λ‹€.

  • (Int, Int, Int, Int) 4 Integer Tuple νƒ€μž…μ˜ upc
  • String νƒ€μž…μ˜ qrCode

ν•˜μ§€λ§Œ Barcode enum 이 κ°–λŠ” 값은 사싀상 Associated Value의 νƒ€μž…μ„ μ •μ˜ν•  뿐 이 κ°’ μžμ²΄λŠ” μ½”λ“œμƒ μ–΄λ– ν•œ μ‹€μ§ˆμ  μ˜λ―Έλ„ 갖지 μ•ŠλŠ”λ‹€. Beverage와 λΉ„κ΅ν•΄λ³΄μž.


enum Beverage: CaseIterable {
    case coffee, tea, juice
}

var myBeverage: Beverage
myBeverage = .coffee

Beverage enum type 은 coffee, tea, juice λ₯Ό 자기 μžμ‹ μ„ κ°’μœΌλ‘œ κ°–λŠ”λ‹€. 이 값은 κ°’ μžμ²΄κ°€ μ½”λ“œμƒμ—μ„œ μ‹€μ§ˆμ  의미λ₯Ό κ°–λŠ”λ‹€.


μ΄λ²ˆμ—λŠ” μœ„ Beverage λ₯Ό κΈ°μ–΅ν•˜λ©° Barcode λ₯Ό μ‚΄νŽ΄λ³΄μž.

var productBarcode: Barcode
productBarcode = .upc(8, 85909, 51226, 3)
print("productBarcode is '\(productBarcode)'")      // productBarcode is 'upc(8, 85909, 51226, 3)'

productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
print("productBarcode is '\(productBarcode)' now")  // productBarcode is 'qrCode("ABCDEFGHIJKLMNOP")' now
  1. Barcode νƒ€μž…μ˜ λ³€μˆ˜ productBarcodeλ₯Ό μ„ μ–Έν•œλ‹€.
  2. λ³€μˆ˜ productBarcode 에 Associated Tuple Value 둜 (8, 85909, 51226, 3) λ₯Ό κ°–λŠ” Barcode.upc 값을 ν• λ‹Ήν•œλ‹€.
  3. μ΄λ²ˆμ—λŠ” λ³€μˆ˜ productBarcode λŠ” Associated Tuple Value ("ABCDEFGHIJKLMNOP")λ₯Ό κ°–λŠ” Barcode.qrCode 값을 ν• λ‹Ήν•œλ‹€.


이λ₯Ό μ •λ¦¬ν•˜λ©΄ λ‹€μŒκ³Ό κ°™λ‹€.

Beverage 의 κ°’ coffeeκ°€ μ‹€μ§ˆμ μΈ 값을 κ°–λŠ” 것과 달리 Barcode 의 κ°’ upcλ‚˜ qrCodeλŠ” κ°’ μžμ²΄λ‘œμ¨λŠ” μ‹€μ§ˆμ μΈ μ˜λ―Έκ°€ μ—†λ‹€. Barcode 의 κ°’ upc λ‚˜ qrCode λŠ” κ°€μ§ˆ 수 μžˆλŠ” Associated Value 의 Type 을 μ •μ˜ν•  뿐이닀.
μ‹€μ œλ‘œ 의미λ₯Ό κ°–λŠ” 값은 (8, 85909, 51226, 3) λ˜λŠ” ("ABCDEFGHIJKLMNOP")와 같은 Associated Tuple Valueκ°€ μ €μž₯ν•˜κ³  μžˆλŠ” 값이닀.

λ˜ν•œ Beverage νƒ€μž…μ˜ μƒμˆ˜ λ˜λŠ” λ³€μˆ˜κ°€ κ°’μœΌλ‘œ coffee와 teaλ₯Ό λ™μ‹œμ— κ°€μ§ˆ 수 μ—†λŠ” 것과 λ§ˆμ°¬κ°€μ§€λ‘œ, Barcode νƒ€μž…μ˜ μƒμˆ˜ λ˜λŠ” λ³€μˆ˜ μ—­μ‹œ upcλ‚˜ qrCode 두 κ°€μ§€μ˜ 값을 λͺ¨λ‘ μ €μž₯ν•  μˆ˜λŠ” μžˆμ§€λ§Œ λ™μ‹œμ— κ°€μ§ˆ μˆ˜λŠ” μ—†λ‹€.

3. Switch Statements with Associated Values

μœ„μ—μ„œ μ‚΄νŽ΄λ³Έ Enumeration 을 Switch 에 λ§€μΉ­ν•˜λŠ” 것과 λ™μΌν•˜λ‹€. 단, 이 경우 μ‹€μ§ˆμ μΈ 값이 Associated Values 이 값을 case λ‚΄μ—μ„œ μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” let λ˜λŠ” var에 ν• λ‹Ήν•΄μ•Όν•œλ‹€.

var productBarcode: Barcode
productBarcode = .upc(8, 85909, 51226, 3)
printBarcode(productBarcode)    // UPC: 8, 85909, 51226, 3.

productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
printBarcode(productBarcode)    // QR code: ABCDEFGHIJKLMNOP.


func printBarcode (_ productBarcode: Barcode) {
    switch productBarcode {
    case .upc(let numberSystem, let manufacturer, let product, let check):
        print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
    case .qrCode(let productCode):
        print("QR code: \(productCode).")
    }
}


λ§Œμ•½, Associated Values μ „λΆ€κ°€ ν•„μš”ν•  경우 λ‹€μŒκ³Ό 같이 κ°€μž₯ μ•žμ— μ„ μ–Έν•˜λŠ” κ²ƒμœΌλ‘œ λŒ€μ‹ ν•  수 μžˆλ‹€.

var productBarcode: Barcode
productBarcode = .upc(8, 85909, 51226, 3)
printBarcode(productBarcode)    // UPC: 8, 85909, 51226, 3.

productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
printBarcode(productBarcode)    // QR code: ABCDEFGHIJKLMNOP.


func printBarcode (_ productBarcode: Barcode) {
    switch productBarcode {
    case let .upc(numberSystem, manufacturer, product, check):
        print("UPC : \(numberSystem), \(manufacturer), \(product), \(check).")
    case let .qrCode(productCode):
        print("QR code: \(productCode).")
    }
}



Summary of Associated Values

Associated Values λŠ” Enumeration 의 cases κ°€ μ˜¨μ „νžˆ 자기 μžμ‹ μ„ κ°’μœΌλ‘œ κ°–λŠ” λŒ€μ‹  λ‹€λ₯Έ νƒ€μž…μ˜ 값을 κ°–κ²Œ ν•˜λ©°, μ΄λ•Œ Enumeration 의 cases 값은 κ°€μ§ˆ 수 μžˆλŠ” Associated Values 의 types λ₯Ό μ •μ˜ν•œλ‹€.
Associated Values λ₯Ό μ΄μš©ν•˜λ©΄ μ„œλ‘œ λ‹€λ₯Έ νƒ€μž…μ˜ 값을 ν•˜λ‚˜μ˜ Enumeration 에 μ €μž₯ν•  수 μžˆλ‹€.
단, μ„œλ‘œ λ‹€λ₯Έ νƒ€μž…μ„ λ™μ‹œμ— μ €μž₯ν•˜λŠ” 것은 μ•„λ‹ˆλ‹€.


5. Raw Values πŸ‘©β€πŸ’»

μ•žμ—μ„œ Associated Values λŠ” cases κ°€ 자기 μžμ‹ μ˜ κ°’ 외에 λ‹€λ₯Έ 값을 κ°–λŠ” 것은 λ¬Όλ‘ , μ„œλ‘œ λ‹€λ₯Έ νƒ€μž…μ˜ 값을 μ €μž₯ν•˜κΈ° μœ„ν•΄ μ–΄λ–»κ²Œ μ •μ˜ν•΄μ•Όν•˜λŠ”μ§€λ₯Ό λ³΄μ—¬μ£Όμ—ˆλ‹€.

μ΄λ²ˆμ—λŠ” Associated Values의 λŒ€μ•ˆ 쀑 ν•˜λ‚˜λ‘œ, casesκ°€ 자기 μžμ‹ μ˜ κ°’ 외에 λ‹€λ₯Έ 값을 κ°€μ§ˆ 수 μžˆλŠ” λ°©λ²•μœΌλ‘œ Raw Valuesλ₯Ό μ†Œκ°œν•œλ‹€. Associated Values 와 λ§ˆμ°¬κ°€μ§€λ‘œ 자기 μžμ‹ μ˜ κ°’ 외에 λ‹€λ₯Έ 값을 갖도둝 ν•˜λŠ” 것은 λ™μΌν•˜μ§€λ§Œ, Associated Values 와 달리 동일 νƒ€μž…μ˜ κ°’λ§Œ cases둜 μ €μž₯ν•  수 μžˆλ‹€.

Raw Valuesλ₯Ό μ •μ˜ν•˜λŠ” 방법은 enum을 μ •μ˜ν•¨κ³Ό λ™μ‹œμ— default valuesλ₯Ό μ •μ˜ν•˜λŠ” 것이닀.

Syntax

enum ASCIIControlCharacter: Character {
    case tab = "\t"
    case lineFeed = "\n"
    case carriageReturn = "\r"
}
enum SomeEnumeration: Int {
    case one = 1
    case two = 2
    case three = 3
}

print(SomeEnumeration.one)          // One
print(SomeEnumeration.one.rawValue) // 1
enum SomeEnumeration: String {
    case one = "ν•˜λ‚˜"
    case two = "λ‘˜"
    case three = "μ…‹"
}

print(SomeEnumeration.one)          // One
print(SomeEnumeration.one.rawValue) // ν•˜λ‚˜

Raw ValuesλŠ” String, Character, Integer, Floating-Point Number νƒ€μž…μ΄ κ°€λŠ₯ν•˜λ‹€.
Raw ValuesλŠ” Uniqueν•΄μ•Όν•œλ‹€.

1. Implicitly Assigned Raw Values

Enumerations λŠ” Raw Values λ₯Ό λ³„λ„λ‘œ μ§€μ •ν•˜μ§€ μ•ŠμœΌλ©΄ 첫 case 에 μ•”μ‹œμ (implicit) 0을 ν• λ‹Ήν•œλ‹€. λ§Œμ•½, Integer λ˜λŠ” String Types 의 데이터λ₯Ό λͺ…μ‹œμ (explicit)으둜 지정해 μ €μž₯ν•  경우 λͺ¨λ“  cases 에 값을 λͺ…μ‹œν•  ν•„μš” 없이 ν•˜λ‚˜μ˜ 값을 λͺ…μ‹œν•˜λ©΄ 이후 값은 κ·Έ 값을 기반으둜 μžλ™μœΌλ‘œ μ•”μ‹œμ μœΌλ‘œ ν• λ‹Ήλœλ‹€.

  • Integer Raw Value

Raw Values λ₯Ό Integer Type 으둜 지정 ν›„ μ•„λ¬΄λž€ 값도 λͺ…μ‹œν•˜μ§€ μ•Šμ„ 경우 Swift λŠ” μ•”μ‹œμ μœΌλ‘œ 첫 case λ₯Ό 0 으둜 ν• λ‹Ήλœλ‹€. 우

enum Planet: Int {
    case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}

print(Planet.mercury.rawValue)  // 0
print(Planet.venus.rawValue)    // 1
print(Planet.neptune.rawValue)  // 7

Raw Values λ₯Ό Integer Type 으둜 지정 ν›„ case 에 값을 λͺ…μ‹œμ μœΌλ‘œ μ €μž₯ν•  경우, λͺ…μ‹œμ μœΌλ‘œ μ €μž₯ν•œ case의 λ‹€μŒ μˆœμ„œλΆ€ν„° 1μ”© μ¦κ°€μ‹œν‚¨λ‹€.

enum Planet: Int {
    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}

print(Planet.mercury.rawValue)  // 1
print(Planet.venus.rawValue)    // 2
print(Planet.neptune.rawValue)  // 8


μ•„λž˜μ™€ 같은 경우 10, 20, 30, 40, ... 이 μ•„λ‹Œ 10, 20, 21, 22, ... μ΄λ―€λ‘œ μ£Όμ˜ν•œλ‹€.

enum Planet: Int {
    case mercury = 10, venus = 20, earth, mars, jupiter, saturn, uranus, neptune
}

print(Planet.mercury.rawValue)  // 10
print(Planet.venus.rawValue)    // 20
print(Planet.neptune.rawValue)  // 26


λ§ˆμ°¬κ°€μ§€λ‘œ μ•„λž˜μ˜ κ²½μš°λ„ 2, 3, 4, 5, 6, ..., 9κ°€ μ•„λ‹ˆλΌ 0, 1, 2, 5, 6, ..., 9μ΄λ―€λ‘œ μ£Όμ˜ν•œλ‹€.

enum Planet: Int {
    case mercury, venus, earth, mars = 5, jupiter, saturn, uranus, neptune
}

print(Planet.mercury.rawValue)  // 0
print(Planet.venus.rawValue)    // 5
print(Planet.neptune.rawValue)  // 9


  • String Raw Value

Raw Values λ₯Ό String Type 으둜 지정할 경우 μ•”μ‹œμ μœΌλ‘œ 각 cases의 이름이 String으둜 ν• λ‹Ήλœλ‹€.

enum CompassPoint: String {
    case east, west, south, north
}

print(CompassPoint.east)            // east
print(CompassPoint.east.rawValue)   // east
print(type(of: CompassPoint.east))          // CompassPoint
print(type(of: CompassPoint.east.rawValue)) // String

2. Initializing from a Raw Value

  • With specific cases
enum Planet {
    case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}

let possiblePlanet = Planet.uranus
print(possiblePlanet)   // uranus

λͺ…ν™•ν•˜κ²Œ caseλ₯Ό μ§€μ •ν•˜λ―€λ‘œ, μ–Έμ œλ‚˜ ν•΄λ‹Ήν•˜λŠ” case 의 Enumeration 을 Instance둜 μƒμ„±ν•œλ‹€.


  • With Raw Values

Raw Value λ₯Ό λ°›μ•„ μΌμΉ˜ν•˜λŠ” Enumeration 의 Enumeration 의 case λ₯Ό Optional Instance둜 μƒμ„±ν•œλ‹€.

enum Planet: Int {
    case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}

let possiblePlanet = Planet(rawValue: 7)
print(possiblePlanet as Any)    // Optional(__lldb_expr_18.Planet.neptune)

let impossiblePlanet = Planet(rawValue: 8)
print(impossiblePlanet as Any)  // nil

λ”°λΌμ„œ λ‹€μŒκ³Ό 같이 Optional Binding을 μ΄μš©ν•΄ μ•ˆμ „ν•˜κ²Œ μ²˜λ¦¬ν•˜λŠ” 것이 μ’‹λ‹€.

var positionToFind = 3
if let somePlanet = Planet(rawValue: positionToFind) {
    switch somePlanet {
    case .earth: print("Mostly harmless")
    default: print("Not a safe place for humans")
    }
} else {
    print("There isn't a planet at position \(positionToFind)")
}
Mostly harmless


var positionToFind = 11
if let somePlanet = Planet(rawValue: positionToFind) {
    switch somePlanet {
    case .earth: print("Mostly harmless")
    default: print("Not a safe place for humans")
    }
} else {
    print("There isn't a planet at position \(positionToFind)")
}
There isn't a planet at position 11


var positionToFind = 11
let isThisSafePlanet = { (planetNumber: Int) -> Bool in
    guard let somePlanet = Planet(rawValue: planetNumber) else {
        print("There isn't a planet at position \(planetNumber)")
        return false
    }
    switch somePlanet {
    case .earth:
        print("Mostly harmless")
        return true
    default:
        print("Not a safe place for humans")
        return false
    }
    
}

let safe = isThisSafePlanet(positionToFind)
print("safe: \(safe)")
There isn't a planet at position 11
safe: false

6. Recursive Enumerations πŸ‘©β€πŸ’»

Enumeration 의 case κ°€ λ‹€μ‹œ 자기 μžμ‹ μ„ Associated Values 둜 κ°€μ§ˆ λ•Œ 이λ₯Ό Recursive Enumerations라 ν•˜λ©°, λ°˜λ“œμ‹œ indirect ν‚€μ›Œλ“œλ₯Ό λͺ…μ‹œν•΄μ•Όν•œλ‹€.


enum ArithmeticExpression { // Recursive enum 'ArithmeticExpression' is not marked 'indirect'
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)
}

indirect ν‚€μ›Œλ“œ 없이 μ„ μ–Έν•˜λ©΄ Swift-compiler 에 μ˜ν•΄ μ—λŸ¬κ°€ λ°œμƒλœλ‹€.


enum ArithmeticExpression {
    case number(Int)
    indirect case addition(ArithmeticExpression, ArithmeticExpression)
    indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}

λ°˜λ“œμ‹œ Recursive-case μ•žμ— indirect ν‚€μ›Œλ“œλ₯Ό λΆ™μ—¬μ€˜μ•Όν•œλ‹€.
λ§Œμ•½, enum ν‚€μ›Œλ“œ μ•žμ— indirect ν‚€μ›Œλ“œλ₯Ό μ„ μ–Έν•˜λ©΄ λͺ¨λ“  cases 에 indirect λ₯Ό μ•”μ‹œμ μœΌλ‘œ μ„ μ–Έν•  수 μžˆλ‹€.

indirect enum ArithmeticExpression {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
    case multiplication(ArithmeticExpression, ArithmeticExpression)
}

μœ„ Enumeration ArithmeticExpression.Type은 λ‹€μŒ 3 κ°€μ§€μ˜ arithmetic expressions(μ‚°μˆ  ν‘œν˜„μ‹)을 μ €μž₯ν•  수 μžˆλ‹€.

  • a plain number
  • the addition of two expressions
  • the multiplication of two expressions

이 쀑 additionκ³Ό multiplication cases λŠ” λ‹€μ‹œ arithmetic expressions λ₯Ό Associated Values 둜 κ°€μ§€λ―€λ‘œ ν‘œν˜„μ‹μ˜ 쀑첩을 ν—ˆμš©ν•΄ Recursive μƒνƒœλ₯Ό λ§Œλ“ λ‹€.


(5 + 4) * 2λ₯Ό ArithmeticExpression.Type λ₯Ό μ΄μš©ν•΄ μ„ μ–Έν•΄λ³΄μž. 데이터가 쀑첩(nested)λ˜λ―€λ‘œ, Enumeration μ—­μ‹œ 쀑첩(nested)이 κ°€λŠ₯ν•΄μ•Όν•œλ‹€.

let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))


Recursive Structureλ₯Ό 가진 데이터λ₯Ό λ‹€λ£¨λŠ” κ°€μž₯ 직관적인 방법은 Recursive Function을 μ΄μš©ν•˜λŠ” 것이닀.

func evaluate(_ expression: ArithmeticExpression) -> Int {
    switch expression {
    case .number(let value): return value
    case let .addition(lhs, rhs): return evaluate(lhs) + evaluate(rhs)
    case let .multiplication(lhs, rhs): return evaluate(lhs) * evaluate(rhs)
    }
}

evaluate(_:)의 첫 번째 case λŠ” Optional Binding ν•˜λ“― ArithmeticExpression.Type μœΌλ‘œλΆ€ν„° Intλ₯Ό λ°˜ν™˜ν•œλ‹€.
evaluate(_:)의 두 λ²ˆμ§Έμ™€ μ„Έ 번째 case λŠ” 첫 번째 case λ₯Ό μ·¨ν•˜λ„λ‘ Recursive Function으둜 μž‘μ„±λ˜μ—ˆλ‹€.

ArithmeticExpression와 evaluate(_:)의 ꡬ쑰가 λͺ¨λ‘ Recursive인 것을 확인할 수 μžˆλ‹€.

print(evaluate(five))       // 5
print(evaluate(four))       // 4
print(evaluate(sum))        // 9
print(evaluate(product))    // 18




Reference

  1. β€œEnumerations.” The Swift Programming Language Swift 5.7. accessed Nov. 1, 2022, Swift Docs Chapter 7 - Enumerations.