Generics(제네릭)

2023. 2. 27. 23:43개발/Swift

1. 제네릭 정의

Write Codes that works for multiple types and specify requirements for those types.

 여러타입에서 사용 가능한 타입.(범용 타입이라고 봐도 무방함.)

 

2. 제네릭의 필요성

 제네릭을 한번 선언하면 사용 할 때마다 타입을 지정할 수 있어서 코드를 반복구현하지 않을 수 있음.

 

3. 제네릭 문법

 Fuction

   • 타입파라미터를 <T>로 지정하고, 파라미터에서 타입으로 사용한다.

   • <T: 제약조건> 형식으로 제네릭 타입을 제약할 수 있다.(프로토콜 제약, 클래스 제약 두가지)

func printData<T: Equatable>(_ data: T) { print(data) }
printData(8) //"8"

 

 Struct, Class

   • 타입파라미터를 <T>로 지정하고, 파라미터에서 타입으로 사용한다.

   • Struct, Class 내 메서드는 타입파라미터를 따로 지정하지 않고 바로 사용한다.

struct Fruits<T> {
    var fruit: T
    func printFavoriteFruits(_ item: T) { print("나는 \(fruit)&\(item)를 좋아해.") } //Struct, Class 내 메서드는 타입파라미터를 따로 지정하지 않고 바로 사용한다.
}

var fruits = Fruits(fruit: "사과")
fruits.printFavoriteFruits("바나나") //"나는 딸기&바나나를 좋아해"

class Fruits<T> {
    var fruit: T
    init(_ fruit: T) {
        self.fruit = fruit
    }
    func printFavoriteFruits(_ item: T) { print("나는 \(fruit)&\(item)를 좋아해.") } //Struct, Class 내 메서드는 타입파라미터를 따로 지정하지 않고 바로 사용한다.
}

var fruits = Fruits("딸기")
fruits.printFavoriteFruits("바나나") //"나는 딸기&바나나를 좋아해"

 

 Enum

   • 타입파라미터를 <T>로 지정하고, 파라미터에서 타입으로 사용한다.

   • case명 뒤에 (T)를 표시해서 타입으로 사용한다.

enum Fruits<T> {
    case apple
    case banana
    case orange(T) //case명 뒤에 (T)를 표시해서 타입으로 사용한다.
}

var fruit = Fruits.orange("오렌지")
var countOrange = Fruits.orange(3)

print(fruit) //orange("오렌지")
print(countOrange) //orange(3)

 

 Extension

   • 확장에서는 타입파라미터 명시 없이 사용한다.

class Fruits<T> {
    var fruit: T
    init(_ fruit: T) {
        self.fruit = fruit
    }
    func printFavoriteFruits(_ item: T) { print("나는 \(fruit)&\(item)를 좋아해.") }
}

extension Fruits { //확장에서는 타입파라미터 명시 없이 사용한다.
    func printNumberOneFruit() { print("그 중에 최고는 \(fruit)!") }
}

var fruits = Fruits("딸기")
fruits.printFavoriteFruits("바나나") //나는 딸기&바나나를 좋아해.
fruits.printNumberOneFruit() //그 중에 최고는 딸기!

 

4. 프로토콜에서 제네릭 문법의 사용

 연관타입 지정(다른 자료형처럼 <T> 대신 associatedtype T 사용)
 타입을 Int로 정의했기 때문에 이 클래스에서 T는 Int이다.(typealias 생략하고 바로 타입사용해도 됨)

protocol Fruits {
    associatedtype T: Equatable //연관타입 지정(다른 자료형처럼 <T> 대신 associatedtype T 사용)
    var count: T { get }
    func estimateValuationPrice(_ count: T)
}

class Apple: Fruits {
    typealias T = Int //타입을 Int로 정의했기 때문에 이 클래스에서 T는 Int이다.(typealias 생략하고 바로 타입사용해도 됨)
    var count: T = 100
    func estimateValuationPrice(_ size: Int) {
        print("이 과일의 가치는 \(count * size)원 입니다.")
    }
}

var apple = Apple()
apple.estimateValuationPrice(30) //"이 과일의 가치는 3000원 입니다."