all white cheat sheet Dana’s Swifty Life

[Swift] Pattern 과 Pattern Matching

A pattern represents the structure of a single value or a composite value.

:pushpin: contents

  • for destructing values
  • for full pattern matching
  • Where - 패턴과 결합하여 조건 추가하기

For Destructing Values - 값 추출하는 패턴

Wildcard Pattern

underscore _

for _ in 1...10 {
	// do something ten times
}

Identifier Pattern

값을 변수나 상수 이름에 연결짓는 것

let age = 27

Value-Binding Pattern

Bind : v. 결합하다, 묶다

패턴에 맞는 값을 상수나 변수 이름에 연결짓는 것

let point = (2, 4)

switch point {
	case let (x, y): //(let x, let y) 도 같은 의미
  	print("point: \(x), \(y)")
}

switch point {
  case (let i, _):
  	print("\(i)")
}

switch point {
  case(_, var j):
  	j += 10
  	print("move point up \(j)")
}

Tuple Pattern

let points = [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1)]
// This code isn't valid.
// because the element - in the tuple pattern (x, 0) is an expression pattern
for (x, 0) in points {
    /* ... */
}

괄호안에 element 가 하나인 경우는 tuple pattern 이 적용 안됨.

다음 세개는 다 동일한 의미 (equivalent)

let a = 2
let (a) = 2
let (a) : Int = 2

 

For Full Pattern Matching

Enumeration Case Pattern

switch 문 만 case 를 쓸 수 있는게 아니다!

If, while, guard, for-in 구문 안에서도 case 조건 사용할 수 있다!

let aString = "ABC"
if case "ABC" = aString { // }
  
enum Dish {
 case pasta(taste: String)
 case chicken(withSauce: Bool)
 case airRice
}
  
var dishes = [Dish]()
var myDinner : Dish = .pasta(taste: "cream")
dishes.append(myDinner)
if case .pasta(let taste) = myDinner { }
  
myDinner = .chicken(withSauce: true)
dishes.append(myDinner)
while case .chicken(let sauced) = myDinner {
 break
}
  
myDinner = .airRice
dishes.append(myDinner)
if case .airRice = myDinner { }
  
for dish in dishes {
 switch dish {
 case let .pasta(taste): print(taste)
 case let .chicken(sauced): print(sauced ? "양념" : "후라이드")
 case .airRice: print("공기밥")
 }
}

Optional Pattern

let someOptional: Int? = 42
// Match using an enumeration case pattern.
// optional은 enum 으로 구현되어있음 .some(Wrapped), .none
if case .some(let x) = someOptional {
    print(x)
}

// Match using an optional pattern.
if case let x? = someOptional {
    print(x)
}

optional value로 구성된 배열이 for 반복문 돌 때, nil 아닌 값만 수행되도록 하는 방법

let arrayOfOptionalInts: [Int?] = [nil, 2, 3, nil, 5]
// Match only non-nil values.
for case let number? in arrayOfOptionalInts {
    print("Found a \(number)")
}
// Found a 2
// Found a 3
// Found a 5

Type Casting Pattern

is type

pattern as type

Expression Pattern

let point = (1, 2)
switch point {
case (0, 0):
    print("(0, 0) is at the origin.")
case (-2...2, -2...2):
    print("(\(point.0), \(point.1)) is near the origin.")
default:
    print("The point is at (\(point.0), \(point.1)).")
}
// Prints "(1, 2) is near the origin."

infix operator ~= : pattern match (Precedence group -comparison Precedence)

~= operator를 overloading 해서 expression matching behavior 커스텀하기

// Overload the ~= operator to match a string with an integer.
func ~= (pattern: String, value: Int) -> Bool {
    return pattern == "\(value)"
}
switch point {
case ("0", "0"):
    print("(0, 0) is at the origin.")
default:
    print("The point is at (\(point.0), \(point.1)).")
}
// Prints "The point is at (1, 2)."

 

Where - 패턴과 결합하여 조건 추가하기

let tuples = [(1,2), (1,-1), (1,0), (0,2)]
for tuple in tuples {
  switch tuple {
    case let (x,y) where x == y: print("same")
    case let (x,y) where x == -y: print("minus")
    case let (x,y) where x>y: print("x is bigger than y")
    case (1, _): print("x=1")
    default: print("\(tuple.0),\(tuple.1)")
  }
}

let arrayOfOptionalInts : [Int?] = [nil, 2, 3, nil, 5]
// nil 이 아닌 element 중에 2보다 큰 것
for case let number? in arrayOfOptionalInts where number > 2 {
  print ("Found a\(number)")
}
//Found a 3
//Found a 5
protocol SelfPrintable {
  func printByMyself()
}

struct Person : SelfPrintable { }
extension Int: SelfPrintable { }
extension String: SelfPrintable { }

extension SelfPrintable where Self: BinaryInteger, Self: Comparable {
  func printByMyself() {
    print("BinaryInteger, Comparable 만족하는 경우만 확장")
  }
}

extension SelfPrintable { 
  func printByMyself() {
    print("그외 나머지 경우 확장")
  }
}

Int(10).printByMyself()
String("hello").printByMyself()
Person().printByMyself()
//BinaryInteger, Comparable 만족하는 경우만 확장
//그외 나머지 경우 확장
//그외 나머지 경우 확장

:pushpin: Reference

  • https://outofbedlam.github.io/swift/2016/04/04/PatternMatching/
  • https://docs.swift.org/swift-book/ReferenceManual/Patterns.html#
  • https://alisoftware.github.io/swift/pattern-matching/2016/03/27/pattern-matching-1/ (유용한 패턴 매칭 예시)
  • https://alisoftware.github.io/swift/pattern-matching/2016/03/30/pattern-matching-2/
  • https://alisoftware.github.io/swift/pattern-matching/2016/04/24/pattern-matching-3/