class GenericPoint1<A> {
var x: A
var y: A
init(x: A, y: A) {
self.x = x
self.y = y
}
}
class GenericPoint2<a1> {
var x: a1
var y: a1
init(x: a1, y: a1) {
self.x = x
self.y = y
}
}
// 한글도 가능하다
class GenericPoint3<타입> {
var x: 타입
var y: 타입
init(x: 타입, y: 타입) {
self.x = x
self.y = y
}
}
// 숫자만은 불가능
class GenericPoint3<3> {
var x: 3
var y: 3
init(x: 3, y: 3) {
self.x = x
self.y = y
}
}
제네릭 문법을 사용했다고 해서 전부 제네릭타입으로 선언하지 않아도 된다.
// 전부 제네릭타입으로 작성하지 않아도 된다.
class GenericColor<T> {
var red: T
var green: UIColor
var blue: T
...
}
열거형에서도 사용가능하다
enum Pet<T> {
case dog
case cat
case bird
case etc(T)
}
let animal = Pet.etc("햄스터")
enum Computer<T> {
case cpu(core: T)
case ram(size: Int)
}
let com1 = Computer.cpu(core: "Hex")
let com2 = Computer.cpu(core: 16)
제네릭의 확장
제네릭 타입을 채택한 구조체나 클래스도 확장이 가능하다.
확장에서 타입파라미터를 사용하여도 타입 파라미터를 명시하지 않는데
그 이유는 본체에서 정의한 타입 파라미터를 사용하기 때문이다.
struct Point<T> {
var x: T
var y: T
}
// 확장시에는 타입파라미터<T>를 명시하지 않는다
// 본체의 제네릭에서 정의한 타입 파라미터를 사용하기 때문
extension Point {
func getPoint() -> (T, T) {
return (x, y)
}
}
// where절도 사용가능하다.
extension Point where T == Int {
func distancePointToZero() -> T {
return (x * x) + (y * y)
}
}
제네릭의 타입 제약
제네릭에서 타입을 제약할수도 있다.
제네릭 선언시에 제약조건을 명시하면 된다.
<T: 제약조건>
// == 연산자를 사용하기 위해선 Equatable 프로토콜을 채택해야 한다
func Equal<T: Equatable>(_ x: T, _ y: T) -> Bool {
x == y
}
특정 클래스를 상속한 클래스만 사용가능하도록 제약을주거나
class Person {}
class Professor: Person {}
class Student: Person {}
let person = Person()
let professor = Professor()
let student = Student()
// 특정 클래스를 상속받은 클래스만 사용가능
func personClassOnly<T: Person>(array: [T]) {
}
personClassOnly(array: [person, person])
personClassOnly(array: [professor, professor])
personClassOnly(array: [student, student])
특정 프로토콜을 채택한 타입만 사용가능하도록 제약을 줄 수도 있다.
protocol Person {}
class Professor: Person {}
class Student: Person {}
let professor = Professor()
let student = Student()
// 특정 프로토콜을 채택한 타입만 사용할 수 있다는 제약
func personProtocolOnly<T: Person>(array: [T]) {
}
personProtocolOnly(array: [professor, professor])
personProtocolOnly(array: [student, student])
프로토콜에서의 제네릭
프로토콜에서도 제네릭 타입을 사용할 수 있는데
프로토콜에서는 associatedtype(연관타입)이라는 것을 사용하여
제네릭과 동일한 타입 파라미터를 저장한다.
protocol Person {
associatedtype T
func doSomeThing(_ something: T) -> T
}
class Professor: Person {
typealias T = String
func doSomeThing(_ something: String) -> String {
...
}
}
class Student: Person {
typealias T = Int
func doSomeThing(_ something: Int) -> Int {
...
}
}
당연하게도 제약사항이나 T대신 다른이름을 사용할 수 있다.
protocol Person {
associatedtype Element: Comparable
func doSomeThing(_ something: Element) -> Element
}