-
[Swift] 와일드카드 패턴(switch, tuple, enum, function)공부/Swift 2023. 10. 17. 22:17
평소 코드를 작성할 때 뭔지도 모르고 자연스럽게 썼었는데, 패턴으로 분류되는 문법이었네요.
특히 와일드카드와 튜플은 코딩테스트 문제를 풀 때 코드를 간결하게 작성하는 목적으로 주로 사용했던 것 같습니다.
패턴이란?
'단독 또는 복합 값의 구조를 나타내는 것'
어렵게 써있는 말이지만, 단순하게 표현의 일환이라고 생각하면 되겠습니다.
특히, switch, guard, if, for등의 키워드와 함께 사용할 때 강력합니다.
여러 패턴 중에서 와일드카드에 대해 어떻게 적용하는지 예제 위주로 설명하겠습니다.
와일드카드 패턴
와일드카드 식별자가 위치한 곳의 값은 무시합니다.
와일드카드 : 0개 이상의 문자로 대체할 수 있는 밑줄 _
와일드카드 패턴 : 일치하는 모든 값을 무시하는 밑줄 _와일드카드는 값을 해체하거나 무시하는 패턴중 하나입니다.
와일드카드 식별자는 아마 Xcode의 노란색 에러로 만났을 것이라 생각합니다.
CMD + B 를 누를 때 마다 날 반겨주는 한줄기 빛 쉽게 말해서 이 자리에 변수가 등장해도 저장하지 않고 버리겠단 의미입니다. 와일드카드는 읽기 쉽고 유지 관리가 가능한 코드를 만드는 데 정말 중요합니다. 필요한 정보만 저장해 중복된 변수 사용으로 인한 문제를 방지할 수 있습니다.
Function에서 인자의 라벨을 와일드카드를 사용해 생략
func addNumbers (one: Int, two: Int) -> Int { return one + two } print(addNumbers(one: 1, two: 2))
func addNumbers (_ one: Int, _ two: Int) -> Int { return one + two } print(addNumbers(1, 2)) // 프로그래머스 swift 문제를 풀면 항상 이런식으로 되어있죠!
생략을 통해 깔끔한 함수가 만들어졌습니다.
주의할 점이 있다면, 지금과 같이 함수의 이름이 명확한 경우엔 괜찮지만 복잡한 기능을 담당하는 함수에선 과도한 생략이 가독성을 해치는 결과를 초래할 수 있으니 적절히 사용하는 것이 중요하겠습니다.
Tuple component에서 사용한 와일드카드
let nameAge = ("Antony", 28) switch nameAge { case ("Antony", _): print("Antony 입니다.") default: print("") }
위 switch를 활용하면 튜플의 이름이 "Antony"인 경우에만 출력이 이뤄지겠습니다.
이처럼, 와일드 카드가 존재하는 값은 무시하고, 와일드카드가 없는 실존 값만 비교하도록 할 수 있습니다.
열거형에서 Tuple의 와일드카드를 활용
enum PersonState { case running(Int) case jumping(Int, Int) // 수평, 수직 속도 case walking(Int) case sitting case sleeping func getHorizontalPosition() -> Int { switch self { case .sitting, .sleeping: return 0 case .walking(let kmph), .running(let kmph): return kmph case .jumping(let speed, _): return speed } } } // https://medium.com/macoclock/the-wildcard-pattern-in-swift-8f0277350941
.jumping의 경우 수직 방향의 속도는 관심이 없기 때문에 수평 속도만 사용했습니다.
함수의 결과를 사용하지 않을 때 사용
_ = addNumbers(3, 4) var arr = [1,2,3,4,5] let _ = arr.popLast() print(arr)
저는 이런식으로 주로 사용합니다.
위 사진은 코딩테스트에서 처음 들어오는 입력이 필요없어서 생략을 위해 사용했습니다. (let 유무는 상관없습니다.)
또한, Stack/Heap 관련 문제에서 원소의 값은 필요없고 제거만 핵심 목적일 때도 사용했습니다.
고차함수의 클로저에서 활용해보기
방법 1
let names = [("James", 17), ("Tom", 16), ("Robert", 18)] let result = names.filter { (name, _) in if name == "Tom" {return false} else {return true} } print(result) // [("James", 17), ("Robert", 18)] // https://medium.com/macoclock/the-wildcard-pattern-in-swift-8f0277350941
Tom과 일치하는 것을 제외하고, 나머지 이름만 출력합니다.
방법 2
let names = [("James", 17), ("Tom", 16), ("Robert", 18)] let result = names2.filter{ $0.0 != "Tom" } print(result) // [("James", 17), ("Robert", 18)]
저는 사실 위의 방식보단 이렇게 클로저 표현식의 '$0' 문법을 사용하는걸 좋아합니다.
훨씬 깔끔해서 보기 좋은 것 같습니다.
방법 3
let names: [(name: String, age: Int)] = [("James", 17), ("Tom", 16), ("Robert", 18)] let result = names.filter{ $0.name != "Tom" } print(result) // [("James", 17), ("Robert", 18)]
시간이 급한게 아니라면 이렇게 타입을 명시합니다.
지금은 따로 Struct를 선언한게 아니기 때문에 튜플타입으로 명시했습니다. 가독성이 훨씬 좋은 코드로 보여지네요.
override를 할 때 매개변수 대신 사용
class MyView: UIView { override func draw(_ ret: CGRect) { // ret 변수 사용하는 경우 } }
하지만 override 과정에서 ret을 사용하지 않는다면 이렇게 수정할 수 있습니다.
class MyView: UIView { override func draw(_ _: CGRect) { // CGRect를 사용하지 않고 그리기 } }
결론
와일드카드는 읽기 쉽고 관리가 용이한 코드를 작성하는데 중요한 역할을 합니다.
좋은 변수명을 사용하고 와일드카드를 활용한다면 클린 코드를 작성할 수 있을 것 입니다.
참고
https://docs.swift.org/swift-book/documentation/the-swift-programming-language/patterns/
https://medium.com/macoclock/the-wildcard-pattern-in-swift-8f0277350941