Where
-일반적으로 타입이나 타입 매개변수에 조건을 추가하는데 사용된다.
-where 절은 크게 두 가지 용도로 사용된다.
1. 패턴과 결합하여 조건 추가
2. 타입에 대한 제약 추가
ex) 제네릭 함수에서 where
func generic<T>(number : T) where T : Equatable{
print(number)
}
where은 조건을 추가해주는데 사용한다고 했다.
위 코드에서 generic 함수의 T타입은 where 절을 통해 Equatable 프로토콜도 준수해야 한다는 조건을 추가해주었다.
패턴과 결합한 where절
-값 바인딩 패턴과 와일드 카드 패턴과 결합한 where 절을 보자.
let tuples : [(Int, Int)] = [(1, 2), (1, -1), (1, 0), (0, 2)] //튜플형 배열 생성
for tuple in tuples {
switch tuple {
case let (x, y) where x == y :
print("x == y")
case let (x, y) where x == -y :
print("x == -y")
case let (x, y) where x > y :
print("x > y")
case (1, _) :
print("x == 1")
case (_, 2) :
print("y == 2")
default:
print("default")
}
}
첫 번째부터 세 번째 case는 값 바인딩 패턴과 함께한 where 절, 나머지 case는 와일드 카드 패턴이다.
튜플 배열 요소를 x, y로 값 바인딩해주고, where 절의 조건을 추가하여 일치할 때 해당 코드가 실행된다.
이렇게 값 바인딩과 where절을 함께 사용했을 때, 두 장점을 사용할 수 있어서 좋은 코드를 작성할 수 있음.
ex) 논리 연산자를 추가한 where절
let tuples : [(Int, Int)] = [(1, 2), (1, -1), (1, 0), (0, 0)] //튜플형 배열 생성
var repeatCount : Int = 0
for tuple in tuples {
switch tuple {
case let (x, y) where x == y && repeatCount > 2 :
print("x == y")
case let (x, y) where x > y || repeatCount < 2 :
print("x > y")
default:
print("default")
}
repeatCount += 1
}
위의 코드같이 where절에 논리연산자를 추가해서 여러 개의 제약 조건들을 만들어줄 수도 있다.
옵셔널 패턴과 결합한 where절
let optionals : [Int?] = [nil, 2, 3, nil, 5]
for case let number? in optionals where number > 2 {
print(number)
}
//3, 5
위 코드는 옵셔널 패턴과 where 절을 결합하여 쓴 코드다.
number는 두가지의 조건을 충족해야 한다.
1. 옵셔널 패턴을 통한 옵셔널 요소에 값이 존재하는지
2. where절을 통한 number > 2 조건이 충족하는지
이 두 가지의 조건이 충족할 때 내부 코드가 실행된다.
타입 캐스팅 패턴과 결합한 where절
ex) is와 where
let someValue : Any = "ABC"
switch someValue {
case let value where value is Int :
print("Int")
case let value where value is String :
print("String")
case let value where value is Double :
print("Double")
default :
print("default")
}
//"String"
ex) as와 where
var things : [Any] = []
things.append(10)
things.append(0.0)
things.append("hello")
things.append((3.0, 5.0))
for thing in things {
switch thing {
case let someInt as Int where someInt > 0 :
print("Int \(someInt)")
case let someDouble as Double where someDouble > 0 :
print("Double")
case let someString as String :
print(someString)
case let (x, y) as (Double, Double) where x < y :
print("\(x), \(y)")
default :
print("default")
}
}
/*
Int 10
default
hello
3.0, 5.0
표현 패턴과 결합한 where절
let point : (Int, Int) = (1, 2)
switch point {
case (0...2, 0...3) where point.0 != 0 && point.1 != 0:
print("point (\(point.0), \(point.1))")
default:
print("default")
}
// point (1, 2)
프로토콜 익스텐션에 where 절을 사용하기.
-익스텐션이 적용된 프로토콜을 준수하는 타입 중에 where 절을 통해 조건에 맞는 프로토콜도 준수할 때 익스텐션이 적용되도록 할 수도 있다.
protocol SelfPrintable {
func printSelf()
}
struct Person : SelfPrintable { }
extension Int : SelfPrintable { }
extension UInt : SelfPrintable { }
extension String : SelfPrintable { }
extension Double : SelfPrintable { }
extension SelfPrintable where Self : FixedWidthInteger, Self : SignedInteger {
func printSelf() {
print("FixedWidthInteger와 SignedInteger를 준수하면서 SelfPrintable까지 준수하는 타입 \(type(of: self))")
}
}
extension SelfPrintable where Self : CustomStringConvertible {
func printSelf() {
print("CustomStringConvertible와 SelfPrintable를 준수하는 타입 \(type(of: self))")
}
}
extension SelfPrintable {
func printSelf() {
print("그 외 SelfPrintable을 준수하는 타입 \(type(of: self))")
}
}
Int(-8).printSelf() //FixedWidthInteger와 SignedInteger를 준수하면서 SelfPrintable까지 준수하는 타입 Int
UInt(8).printSelf() //CustomStringConvertible와 SelfPrintable를 준수하는 타입 UInt
String("Jiho").printSelf() //CustomStringConvertible와 SelfPrintable를 준수하는 타입 String
Double(0.0).printSelf() //CustomStringConvertible와 SelfPrintable를 준수하는 타입 Double
Person().printSelf() //그 외 SelfPrintable을 준수하는 타입 Person
이렇게 SelfPrintable의 익스텐션에 where 절을 추가하여
조건에 맞는 프로토콜을 모두 준수하는 타입만 해당 코드를 사용할 수 있도록 만들 수 있다.
Reference:
-야곰님의 Swift 문법 개정 3판
'Swift' 카테고리의 다른 글
메모리 안전에 관하여 (0) | 2023.03.17 |
---|---|
Error Handling(에러 처리)에 관하여 (0) | 2023.03.16 |
패턴에 관하여 (0) | 2023.03.15 |
Nested Types(중첩 타입)에 관하여 (0) | 2023.03.13 |
타입 캐스팅에 관하여 (0) | 2023.03.13 |