스닥
Playground
스닥
전체 방문자
오늘
어제
  • 분류 전체보기 (125)
    • 개발자 기본기 (1)
    • Swift 아키텍처 (6)
    • iOS 개발 (55)
      • Swift (12)
      • UIKit (17)
      • SwiftUI (9)
      • CoreData (9)
      • MusicKit (4)
      • WebKit (2)
      • 개발 환경 (0)
      • WatchOS (2)
    • 애플 개발자 아카데미 (4)
    • 막 쓰는 개발일지 (0)
    • 운영체제 (4)
    • 네트워크, 서버 (16)
      • Network (9)
      • Server (7)
    • 알고리즘 (8)
    • C언어 (7)
      • 함수 (7)
    • 하루 이야기 (23)

블로그 메뉴

  • GitHub계정
  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • C 언어
  • ios rendering
  • dfs
  • 알고리즘
  • Server
  • Core Animation
  • 깊이 우선
  • ip주소
  • 너비 우선
  • BFS
  • 트리
  • 서버
  • 자료구조
  • docker
  • swift performance
  • SWIFT
  • core data
  • 도커
  • 문자열 복사
  • struct class 성능

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
스닥

Playground

[SwiftUI] Generics 타입 제약 (Type Constraints) 다루기
iOS 개발/SwiftUI

[SwiftUI] Generics 타입 제약 (Type Constraints) 다루기

2022. 3. 20. 23:29

 

 

 

 

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
    스닥
    스닥
    https://github.com/feldblume5263

    티스토리툴바