Generics 함수의 타입매개변수에는 특별한 제약을 걸어주지 않으면 어떤 타입도 들어올 수 있습니다ㅎㅎ
하지만, 아무 타입이나 들어왔을 때 문제가 생기는 경우가 있습니다.
바로 우리의 함수 내부 로직이 특정 성격을 가지는 타입을 다룰 때인데요!
공식문서의 예시를 들어볼게요!
배열에서 문자열을 찾는 함수입니다.
예를들어 ["aa", "bc", "de", "fgh"] 이런 배열이 있을 때, "bc"를 검색한다면 해당 index값인 1을 반환하고,
"a"를 검색하면 일치하는 문자열이 존재하지 않기 때문에 nil을 반환하는 함수이죠!
func findStringIndex(array: [String], valueToFind: String) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
이 함수를 우리가 알고 있는 대로 Generics로 구현해볼까요??
타입 매개변수를 걸어주고, 매개변수들이 해당 매개변수 타입을 가지도록 하면 되겠죠?
func findStringIndex<T>(array: [T], valueToFind: T) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
근데, 이렇게 잘 했는데 컴파일 자체가 되지 않은 문제가 발생합니다.
"Binary operator '==' cannot be applied to two 'T' operands" 이런 오류를 발생시킨 채로요!!
아니?? 앞 글에서 Swap 할 때는 문제없이 됐잖아?? 왜 갑자기 얘는 안되는거지??
우리가 Swap에서 했던 일련의 로직, 즉 변수를 다른 변수에 담는 과정은 단지 변수의 주소값을 복사하고 덮어쓰는 것에 불과하기 때문에
모든 타입에서 가능합니다.
let temp = a
a = b
b = temp
하지만, 사칙연산이나 서로 같은 수를 비교하는 작업은 우리가 임의로 생성한 구조체와 같은 타입 등에서는 불가능합니다.
지금 위의 함수에서 오류가 난 부분은 ==, 즉 비교연산자에서 오류가 발생했죠??
이는 비교연산자는 T에 들어올 수 있는 모든 타입에서 작동하지 않기 때문입니다.
자, 이런식으로 T에는 Equtable protocol을 따르는 친구들만 들어올 수 있어! 라고 타입제약을 걸어주면
func findStringIndex<T: Equatable>(of valueToFind: T, array: [T]) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
print(findStringIndex(of: "bc", array: ["aa", "bc", "de", "fgh"]) ?? "no value")
비교 연산자 부분이 문제없이 컴파일 됩니다.. 비교 연산자가 가능한 친구들만 들어온다고 컴파일러가 이제는 미리 알고 있으니까요ㅎㅎ
조금 다른 예시를 들어볼까요?
다음과 같이 곱셈을 하는 Generics함수를 만든다고 해봅시다.
곱할 수 있는 숫자는 * 연산자 하나로 곱해지긴 하지만, 지금은 연습하는 거니깐
곱셈이 가능한 숫자들을 곱해주는 함수를 하나 만들어볼까요?
func multipleAnything<T>(hls: T, rhs: T) -> T {
return hls * rhs
}
print(multipleAnything(hls: 3.8, rhs: 3.5))
print(multipleAnything(hls: 3, rhs: 3))
이 경우에, 당연히 오류를 내뱉습니다.
만약에 String이 들어가면 곱해질 수 가 없으니까요ㅎㅎㅎ
이 경우에는 숫자여야 곱할 수 있겠죠?
func multipleAnything<T>(hls: T, rhs: T) -> T where T: BinaryFloatingPoint {
return hls * rhs
}
다음과 같이 곱셈 함수를 만들어주면, Int, Float 상관없이 곱셈이 가능합니다.
이렇게 아예 새로운 사용자 정의 연산자를 만드는 방법도 있습니다.
infix operator **: MultiplicationPrecedence
func **<T>(hls: T, rhs: T) -> T where T: BinaryFloatingPoint {
return hls * rhs
}
print(3.8 ** 3.5)
'iOS 개발 > SwiftUI' 카테고리의 다른 글
[SwiftUI] @escaping에 대해서 (2) | 2022.04.11 |
---|---|
[SwiftUI] inout은 어떻게 작동하는가 (C언어의 Call by Reference와 비교) (0) | 2022.03.21 |
[SwiftUI] ForEach에서 \.self를 사용하는 이유와 id 중복 문제 해결 방법 (0) | 2022.03.13 |
[SwiftUI] json parsing 방법 (0) | 2022.03.10 |
[SwiftUI] View 가독성을 늘리는 3가지 방법 (View 쪼개기) (0) | 2022.03.10 |
[SwiftUI] View protocol과 body 변수에 대한 고찰 (some 키워드를 사용하는 이유) (0) | 2022.02.25 |
[Swift UI] @State에 대한 아주 얕은 고찰 (0) | 2021.11.07 |
[SwiftUI] Swift UI에 대한 첫인상 (2) | 2021.11.07 |