[SWIFT] Patterns, Pattern Matching - 패턴과 패턴매칭 (2)

2021. 1. 16. 06:23SWIFT

반응형

이전 글에 이어서 SWIFT의 문법 패턴과 패턴 매칭에 대해 더 알아볼게요.

 

이전 글을 읽지 않은 분이면 이전과 이어지기 때문에 같이 보는게 좋을 것 같아요.

 

[SWIFT] Patterns, Pattern Matching - 패턴과 패턴매칭 (1)

오랜만에 SWIFT 문법에 대해 작성을 해보네요..!! 오늘은 SWIFT 문법의 패턴과 패턴 매칭에 대해 작성해볼까 합니다. 딱 패턴, 패턴 매칭 두 단어를 듣고 오는 느낌은 어떻나요? 패턴은 어떤 구조를

dongminyoon.tistory.com

그럼 앞에서 봤다는 것을 전제로 오늘 포스팅을 진행해볼게요.

 

패턴들을 크게 2가지 범주로 나눌 수 있을 것 같아요.

값을 해제(추출)하거나 무시하는 패턴, 패턴 매칭을 위한 패턴

 

그렇다면 이전 글의 패턴들은 대체적으로 어떤 성질을 가지고 있었을까요?

와일드 카드 패턴, 식별자 패턴, 값 바인딩 패턴, 튜플 패턴

 

전부 값을 가져오거나 어딘가에 할당한다는 특징이 있었던 것 같죠?

 

그렇다면 오늘은 패턴 매칭을 위한 패턴들에 대해 알아볼게요.

 

 

열거형 케이스 패턴(Enumeration Case Pattern)

Enum 타입을 쓸 때, 보통 case와 매칭을 시켜서 각 데이터들을 실행시켰죠?

근데 이 case 구문을 if, while, guard, for-in 구문과도 연결하여 사용할 수 있습니다.

 

즉, 열거형 타입을 case와 매칭시키는 것입니다.

 

에시로 볼게요.

let someValue = "ABC"

if case "ABC" = someValue {
    print("someValue is ABC")
}

우선 String을 이용해서 보통 사용했던 if 문과는 다르게 case로 연결한 것이 보이시죠?

당연히 someValue의 값이 "ABC" 값과 같으니 if문 안의 구문이 실행되겠죠?

 

지금까지 흔히 사용했던 if와는 다르지만 switch 구문에서 사용되는 case를 사용했죠.

아마 저 구문으로 봐서 저희가 사용하던 switch 구문도 내부적으로는 저렇게 동작하고 있다는 것을 알 수 있어요..‼️

 

그럼 다음으로 열거형 타입을 이용해서 case 구문과 연결해볼게요.

enum Job {
    case student(school: String)
    case programmer(skill: String, company: String)
    case qa(company: String)
}

let firstJob: Job = .student(school: "Ajou Univ")

if case .student(let school) = firstJob {
    print("I'm student in \(school)")	// I'm student in Ajou Univ
}

let secondJob: Job = .programmer(skill: "iOS", company: "N")

if case .programmer(let skill, let company) = secondJob {
    print("I'm \(skill) programmer in \(company)")	// I'm iOS programmer in N
}

열거형 타입을 if문과 연결해서 사용한 것을 알 수 있죠.

그리고 연관값이 있는 경우에는 위와 같이 사용하면 되는데, 이 경우도 이전 포스팅에서 값 바인딩 패턴을 언급했었죠..⁉️

 

이렇듯, case와 매칭시키는 것을 열거형 케이스 패턴이라고 합니다.

 

 

옵셔널 패턴(Optional Pattern)

옵셔널 패턴은 옵셔널 타입을 이용해 값을 추출하거나 매치해서 사용할 때 사용할 수 있습니다.

 

SWIFT 내부적으로 옵셔널 타입도 열거형 타입으로 이루어져 있는데, 그렇기 때문에 지금까지 알아보았던 매칭들과 비슷하게 사용할 수 있어요‼️

 

역시 예제로 알아볼게요.

let optionalValue: Int? = 100

if case .some(let value) = optionalValue {
    print(value)	// 100
}

if case let value? = optionalValue {
    print(value)	// 100
}

 

아까 위에서 말했지만, SWIFT의 옵셔널 타입이 열거형(enum)으로 이루어져 있기에 가능한 패턴입니다‼️

옵셔널은 some, none 두 가지의 케이스로 이루어져 있는데, 그렇기 때문에 위의 some을 사용해서 가능한 점을 알아주세요~

 

some의 경우 연관값을 가지는데, 그 연관값이 여러분들이 주로 옵셔널 바인딩을 해서 사용하는 값입니다.

옵셔널 패턴의 경우에도 옵셔널 바인딩처럼 사용할 수 있는데, 값 바인딩 패턴과 결합해서 옵셔널을 사용한 것을 알 수 있죠?

 

지금까지의 패턴들과 비슷해서 이해하기 크게 어렵지 않으리라 생각해요 🤞

 

 

표현 패턴(Expression Pattern)

표현 패턴은 SWIFT의 표준 라이브러리의 연산자인 ~= 연산자의 연산 결과가 true를 반환하여 매칭시키는 패턴입니다.

~= 연산자는 범위를 지정해서 값을 확인하는 연산자입니다.

 

이 연산자는 switch 구문에서 내부적으로 불려서 사용되고 있는데요.

그렇다면, 이 패턴을 알아보기 전에 ~= 연산자의 사용을 보고 switch 문에서 어떻게 사용되는지 알아볼게요.

switch 10 {
case 0...10:
    print("10 is in 0...10")
default: 
    print("10 is not in 0...10")
}    // 10 is in 0...10

let value = 10

if 0...10 ~= value {
    print("value is in 0...10")
}    // value is in 0...10

이렇게 범위 안의 값을 찾을 때, 사용할 수 있는 연산자이고 이 연산자는 switch의 case 구문에서 내부적으로 호출해서 쓰이고 있다고 해요.

 

그렇다면 switch 구문에서 활용을 볼게요.

let point: (Int, Int) = (2, 10)

switch point {
case (0...10, 0...10): print("point is in (0, 0) ~ (10, 10)")
default: print("point is not in area")
}    // point is in (0, 0) ~ (10, 10)

이렇듯 내부적으로 ~= 연산자가 호출되기 때문에 범위 안의 값으로 할당이 되어 실행되는 것을 확인할 수 있습니다.

 

여기서 이제 이 표현 패턴을 어떻게 활용할까요?

바로 저 ~= 연산자를 오버로딩해서 사용할 때, 그 강인함(?)이 보여질 수 있어요.

 

그렇다면 조금 어...? 할 수 있는 예제를 볼게요.

func ~= (pattern: String, value: Int) -> Bool {
    return pattern == "\(value)"
}

let point: (Int, Int) = (5, 10)

switch point {
case ("5", "10"): print("point is (5, 10)")
default: print("point is not exist")
}    // point is (5, 10)

여기서 뭔가 이상한 점이 보이죠...?

 

원래대로라면 왜 Int와 String 타입을 비교했는데 비교가 되지...?

당연히 default 구문으로 들어가야 하는 것이 아닌가..?

 

하지만 비교가 되어서 다른 구문이 호출되고 있죠?

이것이 바로 표현패턴을 활용해서 더욱 강력하게 사용할 수 있는 점입니다..‼️

 

 

 

이렇게 오늘은 저번 시간에 이어서 SWIFT의 패턴에 대해 알아봤어요.

그동안 아무렇지 않게 사용하던 것일수도 있고 생소한 것일수도 있는데, 

저는 이런 익숙한 것들이 패턴이라고 있어서 사용할 수 있었던 것이 조금 놀라웠네요...☺️

 

오늘 포스팅에서 궁금한 점이나 틀린 점이 있으면 알려주세요 :D

감사합니다.

반응형