-
Swift4 : 제네릭 : #Generics : #왜필요해? : #where키워드 : #제약사항걸기스위프트: Swift/스위프트: 언어자체: 문법 2018. 9. 8. 22:37
안녕하세요 ! 씩이 입니다!
저는 Swift 와 iOS 를 공부하고 연구하는 학생입니다.
같은 분야를 공부하는 분들에게 조금이라도 도움이 주고 싶어서 공부하는 것들을 공유합니다.
제 3자가 있다고 가정하고 설명하기 때문에 존대를 하지 않는점 이해 부탁드립니다.
공유가 미래 라고 생각합니다.
한국의 모든 개발자분들 존경합니다!
- Swift version : Swift 4.2 Swift 언어
- 참고한 것들
- 씩이 Github
- 자료구조 소스파일 있습니다.
- iOS 관련 자료들, 정보들 정리해 두었습니다.
- 스위프트로 구현한 자료구조 : DataStructures in Swift4
- Swift4 : 연결리스트 (1 / 3) : #LinkedList : #DataStructrue : #자료구조
- Swift4 : 연결리스트 (2 / 3) : #LinkedList : #값 추가하기, push, append : #값 삽입하기,insert
- Swift4 : 연결리스트 (3 / 3) : #LinkedList : #값 제거하기, pop, removeLast, remove(at: )
- [스위프트 : 자료구조] 스택: Stack: 자료구조: DataStructure: 쌓기
- [스위프트 : 자료구조] 스택 : Stack : 프로토콜 지향 스택 구현하기
- [스위프트 : 자료구조] 큐 (1 / 4): Queue: #자료구조: #배열로 구현한 큐: #배열의원리
- [스위프트 : 자료구조] 큐 (2 / 4): Queue: #자료구조: #연결리스트: #더블연결리스트: #DoublyLinkedList
- [스위프트 : 자료구조] 큐 (3 / 4): Queue: #자료구조: #Stack으로 구현: #더블스택: #DoubleStack: #제일좋음
- [스위프트 : 자료구조] 큐 (4 / 4): Queue: #자료구조: #RingBuffer: #링버퍼로 구현한 큐: #고정된배열: #마지막!!
- [스위프트 : 자료구조] 큐: Queue: 프로토콜 지향 큐 구현하기
- 스위프트: 트리: Tree: #자료구조: #깊이우선탐색: #레벨정렬탐색: #검색알고리즘: Swift4
- 스위프트: 이진 탐색 트리(1 / 2): #BinarySearchTree: #자료구조: #배열과 비교: #트리: #탐색: #삽입: #삭제
- 스위프트: 이진 탐색 트리(2 / 2): #BinarySearchTree: #자료구조: #배열과 비교: #트리: #탐색: #삽입: #삭제
- [스위프트 : 자료구조] AVL Tree: 자가 균형 트리: #balance: #트리의 높이: #rotation메소드: #성능오짐
- [스위프트:자료구조] 트라이: Trie: 문자열 찾기: 단어 찾기
- [스위프트:자료구조] Heap: 힙 자료구조 (1 / 2) : Heap 이란?
- [스위프트:자료구조] Heap: 힙 자료구조 (2 / 2) : Heap 구현하기
- 스위프트로 구현한 알고리즘 : Algorithms in Swfit4
- [스위프트 : 알고리즘] 재귀호출 (1 / 6) : recursive: 재귀호출 : 재귀함수: 반복문: 팩토리얼: 거듭제곱: 피보나치: 하노이의 탑: 최대공약수
- [스위프트 : 알고리즘] 재귀 : 팩토리얼 (2 / 6) : factorial: 재귀호출 : 재귀함수: 반복문: 팩토리얼: 거듭제곱: 피보나치: 하노이의 탑: 최대공약수
- [스위프트 : 알고리즘] 재귀 : 거듭제곱 (3 / 6) : Power: 재귀호출 : 재귀함수: 반복문: 팩토리얼: 거듭제곱: 피보나치: 하노이의 탑: 최대공약수
- [스위프트 : 알고리즘] 재귀 : 피보나치 수열(4 / 6) : Fibonacci: 재귀호출 : 재귀함수: 반복문: 팩토리얼: 거듭제곱: 피보나치: 하노이의 탑: 최대공약수
- [스위프트 : 알고리즘] 재귀 : 하노이의 탑 (5 / 6) : Hanoi: 재귀호출: 재귀함수: 반복문: 팩토리얼: 거듭제곱: 피보나치: 하노이의 탑: 최대공약수
- [스위프트 : 알고리즘] 재귀 : 최대공약수 (6 / 6) : GCD: 재귀호출: 재귀함수: 반복문: 팩토리얼: 거듭제곱: 피보나치: 하노이의 탑: 최대공약수
- [스위프트:알고리즘] 이진 탐색[1 / 3]: Binary Search: 이진 탐색이 뭐야?
- [스위프트:알고리즘] 이진 탐색[2 / 3]: Binary Search: 이진 탐색: 반복문, 재귀호출로 구현하기
- [스위프트:알고리즘] 이진 탐색[3 / 3]: Binary Search: 이진 탐색: 프로토콜 지향으로 구현하기
- Swift 주제별 분류
- Swift4 : 제어 전달 명령문( Control Transfer Statement ) : #continue, #break, #return 키워드
- Swift4 : 클래스와 구조체 : #값을 대하는 방식 : #참조타입, 값 타입 : #===
- Swift4 : 프로퍼티 : #Property : #get, set : #willSet, didSet
- Swift4 : 메소드 : #Method : #영향력 범위 : #self : #mutating : #값타입 수정
- Swift4 : 프로토콜 1 : #Protocol : #설계 : #요구사항 : #델리게이트 패턴 전처리 (1 / 2)
- Swift4 : 프로토콜 2 : #델리게이트 패턴 : #델리게이션 (2 / 2)
- Swift4 : 제네릭 : #Generics : #왜필요해? : #where키워드 : #제약사항걸기
- Swift4 : 자동 참조 카운팅 : #Automatic Referece Counting : #ARC :#강한참조 : #Strong Reference Cycle : #메모리 누수
- Swift4 : 클로저: Closure: #표현방식: #왜필요해?: #효율적: #간결성: #생략
- [스위프트 : 기초] 서브스크립트 : Subscript : 지름길
제네릭 : Generics
- What is Generics ?
- 제네릭 코드를 사용하면 사용자가 정의한 요구사항에 따라 모든 타입에서 작동할 수 있는 유연하고, 재사용 가능한 함수와 타입을 작성할 수 있습니다.
- 중복을 피하고 코드의 의도를 더 명확하고 추상적인 방법으로 표현할 수 있습니다.
- 예제에는 왜 '제네릭' 이라는 아이디어가 필요했는지, 어떤 불편함이 있었는지에 대해 설명합니다. 아래의 것들이 포함되어 있습니다.
- #제네릭 만든 이유 : inout 키워드 : #위치바꾸기 : #같은타입, 다른타입
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
// inout 키워드는 기본적으로 상수인 매개변수를 변경가능한 변수로 바꿔주는 것.변수여야 매개변수의 값을 바꾸는 작업을 할 수 있으니까요.
// Int 타입의a, b 순서 바꾸는 함수.
let temporaryA = a
a = b // 만약 a, b 의 타입이 다르다면, 이 부분에서 컴파일 에러 발생. 스위프트는 안정성을 중요시 하는 언어라 타입이 다른 변수에 값을 할당할 수 없습니다.
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt) // 앞에 107, 뒤에 3 출력됨.
//inout 키워드가 붙은 매개변수로 값을 전달할 때는 변수인 이름 앞에(&)붙여 전달.
func swapTwoStrings(_ a: inout String, _ b: inout String){ // Stirng 타입의 a, b 위치 바꾸기
let temporaryA = a
a = b
b = temporaryA
}
func swapTwoDoubles(_ a: inout Double, _ b: inout Double) { // Double 타입의 a, b 위치 바꾸기
let temporaryA = a
a = b
b = temporaryA
}
// 이게 뭐하는 짓인가 싶음 = > 제네릭 만듬 개꿀..^^
- 제네릭 타입
- 어떤 곳에 쓸 수 있어?
- 함수, 구조체, 클래스, 열거형 등..
- 제네릭 함수는 위에서 설명한 것과 같이 모든 타입에서 작동할 수 있는 함수입니다. 위의 예제를 제네릭으로 표현하면 아래와 같습니다.
- 아래 예제에는 다음과 같은 것들이 포함됩니다.
- #제네릭 : #타입추론 : #함수에서 제네릭
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
// <T> 부분이 Generics 을 표현하는 것
// <T> 의 T 가 내가 원하는 타입입니다. T가 어떤 타입이냐에 따라 매개변수 a, b 의 타입이 결정되는 것이죠. ( 추상화 )
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt) // 매개변수에 3 , 107 들어오면 컴파일러는 타입추론으로 T 를 Int로 자동 인식.
var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString) // 마찬가지 이유로 T 를 String 으로 자동 인식.
- #구조체 에서 제네릭
struct IntStack { // Int 타입의 스택 , last-in-last-out
var items = [Int]()
mutating func push(_ item: Int) { // push -> 아이템 뒤에 추가.
items.append(item)
}
mutating func pop() -> Int { // pop -> 뒤 아이템 제거
return items.removeLast()
}
}
struct Stack<Element> { // Generics 타입의 스택 -> 모든 타입으로 스택 사용가능
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
var stackOfStrings = Stack<String>() // String 타입으로 사용하고 싶어? 이렇게 하면되
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
stackOfStrings.push("cuatro")
//아래에 그림으로 표현되 있습니다.
- 타입 제약 : Type Constraints
- 타입을 추상화 시켜서 재사용 가능하고 유연한 타입을 만드는 것이 제네릭 이었죠? 그 일반화된 타입에 제약사항을 걸 수도 있습니다.
- 제약사항은 예를 들면 매개변수 타입이 특정 클래스를 상속받아야 한다거나, 특정 프로토콜을 채택해야 한다거나 등입니다.
- 다음 예제에서는 다음과 같은 것들이 포함됩니다.
- #제네릭 타입제약이 필요한 이유 : #Equalable 프로토콜 : #==비교가 가능한 타입들
func findIndex(ofString valueToFind: String, in array: [String]) -> Int? {
// 주어진 String 타입의 배열에서 특정 문자열 찾아서 해당 인덱스 반환하는 함수 입니다.
for (index, value) in array.enumerated() { // enumerated() 은 연속적인 집합 쌍을 반환해주는 array 구조체의 인스턴스 메소드 입니당~
if value == valueToFind { // 주어진 배열에 찾고자 하는 문자열이 있으면
return index // 해당 인덱스를 반환하는 거죠.
}
}
return nil
}
let strings = ["cat", "dog", "llama", "parakeet", "terrapin"]
if let foundIndex = findIndex(ofString: "llama", in: strings) { // "llama" 찾겠쥬?
print("The index of llama is \(foundIndex)")
}
//제네릭 제약사항이 필요한 이유.
func findIndex<T>(of valueToFind: T, in array:[T]) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind { // 컴파일 에러가 발생!!
// 에러의 이유는 모든타입이 == 비교를 할 수 없기 때문입니다.
// 그럼 제네릭을 사용할 수 없는 것일까요? 이 문제 하나 때문에?
// 이 문제가 제네릭에 제약사항이 필요한 이유입니다.
return index
}
}
return nil
}
func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
// <T: Equatable> 제약사항을 걸어줍니다. T 라는 제네릭 타입은 Equatable 프로토콜을 채택한 타입이어야 한다는 것이죠
// Equatable 프로토콜은 ==비교를 할 수 있는 타입들이 채택한 프로토콜입니다.
// 이 제약사항으로 T 에 들어가는 모든 타입은 == 비교를 할 수 있어지겠죠?
for (index, value) in array.enumerated() {
if value == valueToFind { // 컴파일 오류 없이 실행 가능!! good
return index
}
}
return nil
}
- 제네릭을 where 구문으로 확장하기
- extension 과 where 키워드를 활용해서 제네릭을 특정제약사항이 추가되도록 확장할 수 있습니다.
- 위의 Stack 예제를 살짝만 변형한 것입니다^^.
extension Stack where Element: Equatable {
// Stack 구조체에서 generic 타입 Element 가 Equatable 프로토콜을 채택하도록 확장하시오. 라는 의미
func isTop(_ item: Element) -> Bool {
guard let topItem = items.last else {
return false
}
return topItem == item // 확장했으니 == 컴파일 오류 안나쥬?
}
}
'스위프트: Swift > 스위프트: 언어자체: 문법' 카테고리의 다른 글
댓글