티스토리 뷰
안녕하세요 :) Zedd입니다.
오늘은 Patterns에 대해서 알아볼거에요!!XD
Patterns
Patterns(이하 패턴).
패턴이 뭘까요?
Swift에는 뭔가 정형화된 패턴이 있나보네요.
패턴은 단일 값(single value)또는 복합 값(composition value)의 구조로 나타납니다.
예를들어, 튜플 (1, 2)의 구조는 쉼표로 구분된 2개의 요소 리스트입니다.
패턴은 특정 값이 아닌 값의 구조를 나타내므로 다양한 값으로 패턴을 일치시킬 수 있습니다.
예를들어, 패턴(x, y)는 튜플 (1, 2)뿐만아니라 다른 2개의 요소가 들어있는 튜플과도 매치됩니다.
패턴과 값을 일치시키는 것 외에도 복합 값(composition value)의 일부 또는 전부를 추출하여 각 부분을 상수 또는 변수 이름에 바인딩 할 수 있습니다.
Swift에는 두가지 패턴이 있습니다.
어떤 종류의 값과도 일치하는 패턴과
어떤 종류의 값과도 일치하지 않는 패턴이 있습니다.(run time에)
첫번째 패턴 (어떤 종류의 값과도 일치하는 패턴)은 단순 상수, 변수 및 옵셔널 바인딩(Optional Binding)에서 값을 소멸시키는 데 사용됩니다.
여기에는 wildcard 패턴, identifier 패턴 및 이를 포함하는 값 바인딩 또는 튜플 패턴이 포함됩니다.
이러한 패턴에 대한 타입 어노테이션을 지정하여 특정 유형의 값과만 일치하도록 제한을 걸 수 있습니다.
두번째 패턴 (어떤 종류의 값과도 일치하지 않는 패턴)은 전체 패턴 매칭(full pattern matching)에 사용됩니다.
여기서 일치시키려는 값은 런타임에 없을 수 있습니다. 이 패턴에는 열거 케이스 패턴, Optional패턴, 표현패턴 및 타입 캐스팅 패턴이 포함됩니다. 이 패턴에는 switch문 , do-catch, if case, while, guard, for-in문이 있어요.
먼저, 어떤 종류의 값과도 일치하는 패턴에는 wildcard 패턴, identifier 패턴등이 있다고 했는데, 이것들을 먼저 볼게요 ㅎㅎ
Wildcard Pattern
for _ in 1...3 {
// Do something three times.
}
위 코드는 1...3이라는 닫힌 구간에서 현재 값을 무시합니다. 단지 그냥 닫힌 범위인 1...3을 반복할 뿐이죠.
원래같으면 이렇게
for i in 0..<arr.count {
// Do something three times.
}
i라는 변수를 만들어서 이 for루프안에서 i를 사용했었죠.
하지만, 현재 값을 무시하는, 정말 반복만 하고싶다면 _를 사용하여 현재값을 무시할 수 있는거죠.
아..이게 와일드카드 패턴이었군요..!!!!
Identifier Pattern
let someValue = 42
헉....정말 일반적으로 우리가 사용하고 있는건데 말이죠..
위 상수(let)선언해서 someValue는 Int타입의 값 42와 일치하는 Identifier패턴입니다.
일치가 성공하면 값 42는 someValue라는 상수 "이름"에 바인딩(할당) 됩니다.
변수 또는 상수 선언의 왼쪽에 있는 패턴이 Identifier패턴인 경우, Identifier패턴은 암시적으로(implicitly) 값 바인딩 패턴의 하위 패턴입니다.
Value-Binding Pattern
let point = (3, 2)
switch point {
// Bind x and y to the elements of point.
case let (x, y):
print("The point is at (\(x), \(y)).")
}
// Prints "The point is at (3, 2)."
위의 예제에서 튜플 패턴(x, y)의 각 Identifier패턴에 분배합니다. 이 동작으로 인해 switch 케이스들은 case(x, y) 그리고, case (let x, let y)는 같은 값을 찾습니다.
Tuple Pattern
let points = [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1)]
// This code isn't valid.
for (x, 0) in points {
/* ... */
}
let a = 2 // a: Int = 2
let (a) = 2 // a: Int = 2
let (a): Int = 2 // a: Int = 2
Enumeration Case Pattern
Optional Pattern
let someOptional: Int? = 42
// Match using an optional pattern.
if case let x? = someOptional {
print(x)
}
옵셔널 패턴은 for-in구문에서 옵셔널 값의 배열을 반복할 수 있는 편리한 방법을 제공합니다. 이 경우 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
for문에 저렇게 case let을 넣을 수 있다는 것은 처음알았네요 ㅎㅎ..
지금 몇개 다른걸 해봤는데,
var arr = [1,2,3,4,5]
for index in arr{
index = 1//error! cannot assign to value: 'index' is a 'let' constant
}
for-in루프안에서 index를 변경하려고 하면 늘 오류가 났었어요.
근데!!!
var arr = [1,2,3,4,5]
for var index in arr{
index = 1
}
for case var index in arr{
index = 1
}
for-in루프안에서 var index 나, 저기 위에 처럼 case를 사용해서 case var를 사용하면 가능하다는 사실!!!! let으로 선언하면 당연히 안되겠죠?
아무튼 ㅎㅎ...옵셔널 패턴과는 조금 상관없지만, 알아두시면 좋을 것 같아요!!
Type-Casting Patterns
is type
pattern as type
is패턴은 런타임시 해당 값의 타입이 is패턴의 오른쪽에 지정된 타입 또는 해당 타입의 서브클래스와 동일한 경우 값과 일치하게 됩니다.
is패턴은 둘 다 타입 캐스트를 수행하지만, 리턴된 타입은 버리는 점에서, is연산자와 같이 동작합니다.
as패턴은 런타임시 해당 값의 타입이 as패턴의 오른쪽에 지정된 타입 또는 해당 타입의 서브클래스와 동일한 경우 값과 일치합니다.
일치가 성공하면 일치 된 값의 유형이 as 패턴의 오른쪽에 지정된 패턴으로 변환됩니다.
Expression Pattern
let point = (1, 2)
switch point {
case (0, 0):
print("(0, 0)은 원점입니다. ")
case (-2...2, -2...2):
print("(\(point.0), \(point.1))은 원점과 가깝습니다.")
default:
print("점은 (\(point.0), \(point.1)) 입니다.")
}
// Prints "(1, 2)는 원점과 가깝습니다."
저기~~위에서 tuple 패턴에서, 잠깐 표현패턴이 나왔었죠?
표현패턴은 위에서 말했듯이 "값"을 나타내요.
위 예제를 보면, case에서, x나 y같이 변수로 나타내는 것이 아닌, 정말 0,0 이런식으로 "값"을 줬죠?
이게 바로 표현패턴을 사용한거에요.
값뿐만이 아니라, "범위"를 줄 수 도 있네요 ㅎㅎ
그럼 위에서 말한 ~=는 뭐죠..?;;;
처음보는 연산자인데 말이죠.
간단하게 말해서 ~=연산자는 범위를 체크해주는? 간편한 연산자에요.
여기의 예제를 참고하자면,
let n: Int = 100
우리는 어떤 숫자를 가지고 있고, 이 숫자가 10이상인지 100이하인지 확인하고 싶어요.
그럼 어떻게 확인할까요?
if n>=10 && n<=100{
print("10이상, 100이하입니다!")
}
네! 이런방법이 있을 수 있겠죠 ㅎㅎ
그치만 ~=연산자를 사용하면 더 간단해진답니다.
if 10...100 ~= n{
print("10이상, 100이하입니다!")
}
바로 이렇게요!!
깔끔해졌죠?
이 ~=연산자를 "오버로딩" 할 수 도 있답니다.
저기 위의 Point예제를 사용할거에요.
let point = (1, 2)
func ~= (pattern: String, value: Int) -> Bool {
return pattern == "\(value)"
}
switch point {
case ("0", "0"):
print("(0, 0)은 원점입니다.")
default:
print("점은 (\(point.0), \(point.1)) 입니다.")
}
// Prints "점은 (1, 2) 입니다."
자..이상한 점이 한둘이 아니네요. 하나씩 살펴봅시다.
일단 point라는 상수를 tuple로 만들어주었는데, 안의 값은 Int네요.
일단 ~=를 오버로딩한 함수는 조금만 이따가 보기로 하고,
switch문으로 가봅시다.
그런데...
switch point {
case ("0", "0"):
print("(0, 0)은 원점입니다.")
default:
print("점은 (\(point.0), \(point.1)) 입니다.")
}
// Prints "점은 (1, 2) 입니다."
분명히 point는 (Int,Int)였는데..........String으로 case를 만들다니...이게 무슨...
일단 point라는 튜플이 switch문 안으로 들어와서 저 case를 한번 검사할거에요.
그럼 결국 Int와 String을 비교한다는 소리네요.
그것을 가능하게 해주는 것이 바로 위에서 오버로딩한 ~=겠죠? 봅시다.
(~=는 원래 Equatable 프로토콜에 정의되어있는 메소드입니다. Equatable을 더 자세히 알고싶으시다면, < Equatable >를 참고해주세요 XD)
보기전에 ㅎㅎㅎㅎ
~=를 좀 더 알고 봅시다.
"두개의 파라미터가 같은 값으로 일치하는지 여부를 나타내는 Bool값을 반환합니다"
오..근데 Generic Operator라는 말이 보이네요.
그렇다는말은..?뭔가 예상이 가지 않나요?..
바로 이것이 ~=의 원형이라는 것..Generic메소드였네요 ㅎㅎ
그렇다는 소리는, 두 파라미터(a, b)가 Equatable을 준수하기만 한다면,
두 값이 일치하는지 확인할 수 있겠네요.
그럼 왜 ==를 안썼냐;; ==도 Generic연산자인데
네! 대부분의 경우 값이 같은지 안같은지 여부를 판단할 때는 ==연산자를 사용하죠.
하지만 ~=는 패턴매칭 연산자로서, 주로 case문 패턴매칭을 가능하게 해준답니다.
그것이 유일한 차이점이라고 할 수 있겠네요 ㅎㅎ
자. 아까 우리가 오버로딩한 ~=연산자에요.
func ~= (pattern: String, value: Int) -> Bool {
return pattern == "\(value)"
}
간단해요. 왼쪽은 Equatable을 준수하는 String, 오른쪽은 Equatable을 준수하는 Int.
그 둘을 비교하네요!! 물론 value인 Int를 String으로 바꿔서요.
만약 같다면 true를 리턴할테고, 다르다면 false를 리턴하겠죠?
그럼 이렇게만 해줘도 ~=가 알아서 불리냐?...
이 switch문안에서는 어디에도 ~=가 보이지 않는데 말이에요.
네! 불립니다. ~=연산자는 패턴매칭을 위해 case문에서 내부적으로 사용됩니다. case문에서 Equatable값과 일치할 때 이 연산자(~=)는 뒤에서 호출됩니다. (this operator is called behind the scenes.)
이얄ㅋ
자. 이렇게 Swift의 패턴들을 알아보았습니다ㅎㅎ
제가 무심코 사용하던 것들이 "패턴"이었다는 것에 다시한번 놀라네요.
도움이 되었길 바래요 :) 안녕!!
'Swift' 카테고리의 다른 글
Swift ) Nested Types (0) | 2017.12.06 |
---|---|
Swift) dynamic이란? / Realm의 dynamic var는? (8) | 2017.11.17 |
Swift ) Type Casting (2) | 2017.10.23 |
Swift ) Protocols (2) (3) | 2017.10.18 |
Swift ) Method (7) | 2017.10.17 |
- Xcode
- 스위프트 문법
- 제이슨 파싱
- Git
- iOS delegate
- 스위프트
- WWDC
- swift array
- swift sort
- WidgetKit
- 회고
- SwiftUI
- IOS
- WKWebView
- np-hard
- swift 공부
- Combine
- Accessibility
- np-complete
- Swift
- swift delegate
- UIBezierPath
- github
- 피아노
- swift tutorial
- swift3
- actor
- ios 13
- FLUTTER
- fastlane
- Total
- Today
- Yesterday