> For the complete documentation index, see [llms.txt](https://sois-organization.gitbook.io/today-i-learned/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sois-organization.gitbook.io/today-i-learned/swift/undefined-6.md).

# 제네릭

## 제네릭 문법이 필요한 이유

* 같은 기능을 하는 함수인데, 매개변수의 타입이 다른경우는 계속 같은 함수를 만들어줘야돼!
  * swap 하는 함수를 만드는데, Int와 Int를 바꾸는 함수, Double과 Double을 바꾸는 함수 등등.. 굉장히 불편 ^^! → 이런 상황들을 위해서 제너릭 문법이 필요한거임

### 제네릭 필요성

* 타입만 다르고 구현내용이 동일할 때 사용하는 것
* 한 번의 구현으로 모든 타입을 커버하는 것

  * 타입과 관계 없이 한 번의 구현으로 모든 타입을 처리하여 유연한 함수, 구조체, 클래스, 열거형 등을 일반화 가능한 코드로 작성한다.
  * 구현 방법

  ```swift
  func printArray**<T>(array: [T])** {
      for number in array {
          print(number)
      }
  }
  ```

## 제네릭 함수의 정의

### 함수 정의 방법

1. 타입 파라미터

* 타입파라미터 \*\*\*\*는 함수 내부에서 **파라미터의 타입**이나 **리턴형**으로 사용된다. (함수 바디에서도 사용가능)
* 타입 파라미터는 관습적으로 T를 사용한다.
  * 다른 문자를 사용해도 된다. (Upper camel case사용해야함)
* \<T, U>, \<A, B> 등 타입 파라미터를 2개 이상으로 선언할 수 있다.
  * 서로 다른 타입을 사용해야할 때 사용하는 방법이다.

2. 제네릭 타입의 extension

* 타입 파라미터를 명시하지 않고 확장해야한다.
* 본체의 제네릭에서 정의한 타입 파라미터를 사용할 수 있다.
* 단 where을 사용하여 특정 타입으로 제한은 가능하다.

### 나도 모르게 숨어있던 제네릭!

```swift
let array = Array**<String>** = ["Cook",  "Musk"]

let dict = Dictionary**<String, Int>** = ["A": 1, "B": 2]

var optional: Optional**<String>** 
```

* 실제 사용하고자 할 때에는 T가 정의된 위치에 실제 타입을 넣어주어야한다.

### 제네릭의 타입 제약

1. 프로토콜 제약

* 특정 프로토콜을 따르는 타입으로만 치환할 수 있도록 제약 가능하다

2. 클래스 타입 제약

* 특정 클래스와 상속 관계 내에 속하는 클래스만 치환할 수 있도록 제약할 수 있다.

## 프로토콜에서의 제네릭 문법 사용하는 방법

1. 연관타입을 지정 방식

* associatedtype (연관타입) 키워드를 쓰고, 타입 파라미터로 사용할 문자를 작성한다.
  * 프로토콜에서 플레이스 홀더 역할을 한다. (어떤 타입이든 입력되야한다는 것을 제시한다.)

2. 프로토콜 채택 및 연관 타입 사용 방법

* typealias를 사용하여 명식적으로 타입을 치환한다. (생략 가능하다)
* 생략가능하므로, 실 타입을 구현한 함수에서 실제 타입을 사용하기만하면 된다.
