본문 바로가기
Swift

Where절에 관하여

by iOS 개린이 2023. 3. 15.

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