Open Do-hyun-Kim opened 1 year ago
제네릭 타입:
타입이름<타입 매개변수>
제네릭 메서드/함수:
메서드이름<타입 매개변수> (메서드 매개변수...) {...}
제네릭 타입으로 구현한 연결리스트
struct LinkedList<T> {
private var head: Node<T>?
mutating func append(_ value: T) {
let newNode = Node(value: value)
if head == nil {
head = newNode
return
}
var current = head
while current?.next != nil {
current = current?.next
}
current?.next = newNode
}
mutating func insert(_ value: T, at index: Int) {
let newNode = Node(value: value)
if index == 0 {
newNode.next = head
head = newNode
return
}
var current = head
var i = 0
var previous: Node<T>?
while current?.next != nil && i < index {
previous = current
current = current?.next
i += 1
}
previous?.next = newNode
newNode.next = current
}
mutating func remove(at index: Int) -> T? {
if index == 0 {
let value = head?.value
head = head?.next
return value
}
var current = head
var i = 0
var previous: Node<T>?
while current?.next != nil && i < index {
previous = current
current = current?.next
i += 1
}
previous?.next = current?.next
return current?.value
}
func nodeAt(_ index: Int) -> Node<T>? {
var current = head
var i = 0
while current?.next != nil && i < index {
current = current?.next
i += 1
}
return current
}
}
generic
을 이용하여 함수를 짤 수도 있고, 구조체, 클래스, 열거형 타입에서도 사용할 수 있다.<>
를 이용해서 안에 타입처럼 사용할 이름(T)을 선언해주면, 그 뒤로 해당 이름(T)을 타입처럼 사용할 수 있다.,
사용
func swapTwoValues<One, Two> {...}
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let tempA = a
a = b
b = tempA
}
var someInt = 1
var anotherInt = 2
swapTwoValues(&someInt, &anotherInt)
print(someInt, anotherInt)
// 2 1
var someString = "Hi"
var anotherString = "Bye"
swapTwoValues(&someString, &anotherString)
print(someString, anotherString)
// Bye Hi
// 구조체에 선언한 예 (stack을 generic으로 만듦)
struct Stack<T> {
let items: [T] = []
mutating func push(_ item: T) {...}
mutating func pop() -> T {...}
}
let array1: Array<Int> = .init()
let array2 = Array<Int>.init()
print(array1, array2)
// [] []
struct Stack<T> {
var items: [T] = []
mutating func push(_ item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
}
generic 정의 객체를 생성하거나 generic 메서드를 호출할 때 Swift 에서는 생성/호출 직전, generic 타입과 실제 데이터 타입을 바인딩(binding) 하게 된다.
protocol 제약: 특정 프로토콜을 채택하는 타입만 generic으로 사용될 수 있다.
struct SomeStruct<T: SomeProtocol> {
....
}
class 제약: 특정 클래스를 상속하는 클래스 타입만 generic으로 사용될 수 있다.
struct SomeStruct<T: SomeClass> {
....
}
Generic에 대해 설명하시오.
Generic
이란 Type에 유연하게 대처 할 수 있으며 범용적인 코드를 구현 할 수 있다.Generic
을 사용하면 구현한 기능과 타입에 재사용에 용이하도록 구현 할 수 있으며, 코드의 중복을 줄 일 수 있다.Swift
Standard Library
에서는Array
,Dictionary
,Set
등에서 사용을 하고 있다.Generic Function
Generic Functions
제너릭을 사용하고자 하는 메서드 이름 뒤에
<T>
홀화살 괄호와placeholder
제너릭을 위한 타입 매게변수를 써주어 제너릭을 사용할 것임을 명시해준다.제너릭 함수는 실제 타입
Array, Set, String
등 Swift에서 제공되는 타입 대신placeholder
를 사용한다.T
,Element
,U
,Index
placeholder
의 실제 타입은 함수가 호출 되는 순간에 결정된다.placeholder
는 타입 매개변수로 쓰일 수도 있는데, 이 타입 매개변수는 함수를 호출할 때마다 실제 타입으로 치환된다.하나의 타입 매개변수를 갖지 않고 여러 개의 타입 매개변수를 갖고 싶다면 홀화살괄호 기호 안쪽에 쉼표로 분리한 여러 개의 타입 매개변수를 지정해줄 수 있다.
Generic Type Parameter
placeholder
타입은 Type Parameter의 한 예입니다.placeholder
을 파라미터 타입으로 사용하거나 함수의 리턴 타입, 또는 함수 내에서 타입 annotation으로 사용할 수 있습니다.placeholder
의 타입은 함수가 호출 될때 실제 타입(Int
,Double
,String
) 등으로 대체 됩니다.Generic Types
제너릭 타입은
class
,struct
,enum
타입에 선언하여 정의 할 수 있습니다.Generic
은 함수 외에도 자신만의 제너릭 타입(Generic Types) 를 정의 할 수 있습니다.제너릭 타입의 instance 를 생성 할때는
<Type>
을 명시하여 인스턴스를 생성합니다.Extending a Generic Type
Generic Type
을 확장할 때, 익스텐션(extension) 의 정의의 일부로 타입 파라미터 리스트를 제공하지 않아도 된다.Generic Type Constraints
Generic Type Constraints
는 타입 매개변수가 가져야 할 제약 사항을 지정할 수 있는 방법이다.Type Constraints
는 클래스 타입 또는 프로토콜 타입으로만 제약을 줄 수 있다.Generic Type
에 제약을 주고 싶으면 타입 매개변수 뒤에 콜론을 붙인 후 원하는 클래스 타입 또는 프로토콜을 명시하면 된다.where
절을 이용한다.TMI Generics
구체화(Specialization)
과정을 거치며 구현이 이루어집니다.Generics
원소가 지원하는 함수의 목록을 함수 호출 시에 함께 넘겨주는 방식입니다.TMI Generics Specialization
Specialization
Generics를 이용해maxInt(_: _: _:)
,maxDouble(_: _: _:)
,maxString(_: _: _:)
함수를max(_: _: _:)
함수 하나로 만들 었던 것의 정반대 작업을 컴파일러가 수행하는 것을 말합니다.Specialization
를 하면 컴파일 시점에 어떤 타입의 연산을 사용하는지 알 수 있기 때문에 최적화할 여지가 많아 집니다. 하지만 함수를 여러번 복사하고, 복사본이 여러번(@inline) 될 수 있기 때문에 바이너리 사이즈가 커집니다.Specialization
를 통해 구체적인 타입(int
,Double
) 등을 가질 수 있으며, Heap 할당 , Reference Counting, Dynamic Method Dispatch 로 인한 성능 저하를 해결 할 수 있습니다.📝 참고 사이트