๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐ŸŽ iOS/Swift

[Swift] Generic

์•ˆ๋…•ํ•˜์„ธ์š” ์ œ์ธ์ž…๋‹ˆ๋‹ค :)

์˜ˆ์ „์— TIL๋กœ ์ •๋ฆฌํ–ˆ๋˜ Generic์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ๋ธ”๋กœ๊ทธ์—๋„ ํฌ์ŠคํŒ…ํ•ด๋‘๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์•„ ์‡ฝ์ƒฅ ํ•ด์™”์Šต๋‹ˆ๋‹ค ใ…Žใ…Ž

Generic์— ๋Œ€ํ•ด Apple์˜ Swift๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ์ •๋ฆฌํ•ด๋ณด๋ ค ํ•ฉ๋‹ˆ๋‹ค!

Generic์ด๋ž€?

 

generic์€ ํฌ๊ด„์ ์ธ, ํ†ต์นญ์˜ ์ •๋„์˜ ์‚ฌ์ „์ ์ธ ์˜๋ฏธ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
๊ทธ๋ ‡๋‹ค๋ฉด, Apple์—์„œ ์†Œ๊ฐœํ•˜๋Š” generic์— ๋Œ€ํ•ด ํ•œ๋ฒˆ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!

Generic์ด๋ž€ ํƒ€์ž…์— ์˜์กดํ•˜์ง€ ์•Š๋Š” ๋ฒ”์šฉ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
Generic์„ ์‚ฌ์šฉํ•˜๋ฉด ์ค‘๋ณต์„ ํ”ผํ•˜๊ณ , ์œ ์—ฐํ•˜๊ณ  ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Generic์€ Swift์˜ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜๋กœ, Swift ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๋Œ€๋ถ€๋ถ„์€ Generic ์ฝ”๋“œ๋กœ ์ž‘์„ฑ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค.
์‹ค์ œ๋กœ, Generic์„ ์‚ฌ์šฉํ–ˆ๋‹ค๋Š” ๊ฒƒ์„ ์ธ์‹ ๋ชปํ–ˆ๋‹ค๊ณ  ํ•˜๋”๋ผ๋„ Language Guide ์ „์ฒด์—์„œ Generic์„ ์‚ฌ์šฉํ•ด์™”์Šต๋‹ˆ๋‹ค.
๊ทธ ์˜ˆ๋กœ, Swift์˜ Array์™€ Dictionary๋Š” ๋ชจ๋‘ Generic ์ปฌ๋ ‰์…˜์ž…๋‹ˆ๋‹ค. (ํƒ€์ž…์— ๋Œ€ํ•œ ์ œํ•œ์—†์ด Array๋‚˜ Dictionary๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)

Generic Function (์ œ๋„ค๋ฆญ ํ•จ์ˆ˜)

Apple์—์„œ ์ œ๊ณตํ•˜๋Š” ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด Generic์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!

 

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
   let tempA = a
   a = b
   b = tempA
}

 

์œ„์˜ ํ•จ์ˆ˜๋Š” ๋‘ ์ •์ˆ˜์˜ ๊ฐ’์„ ๋ฐ”๊ฟ”์ฃผ๋Š”(swap) ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
์ด ํ•จ์ˆ˜๋กœ ๋“ค์–ด์˜ค๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ๋ชจ๋‘ Intํ˜•์ผ ๊ฒฝ์šฐ์—๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฐ๋ฐ ๋งŒ์•ฝ ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…์ด Int๊ฐ€ ์•„๋‹Œ Double์ด๋‚˜ ๋‹ค๋ฅธ ํƒ€์ž…์ด๋ผ๋ฉด? ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
์™œ๋ƒํ•˜๋ฉด Swift๋Š” ํƒ€์ž…์— ๋ฏผ๊ฐํ•œ ์–ธ์–ด์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค!

๋งŒ์•ฝ Int๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ํƒ€์ž…์— ๋Œ€ํ•ด์„œ swapํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด

 

func swapTwoDoubles(_ a: inout Double, _ b: inout Double) {
   let tempA = a
   a = b
   b = tempA
}

func swapTwoStrings(_ a: inout String, _ b: inout String) {
   let tempA = a
   a = b
   b = tempA
}

 

์œ„์™€ ๊ฐ™์ด ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…์„ ๋ฐ”๊ฟ” ํ•„์š”์— ๋”ฐ๋ผ ํ•จ์ˆ˜๋ฅผ ์—ฌ๋Ÿฌ๊ฐœ ๋งŒ๋“ค์–ด ์ฃผ๋ฉด ๋˜์ง€๋งŒ..
์ด ๊ณผ์ •์ด ๋„ˆ๋ฌด๋‚˜ ๋ฒˆ๊ฑฐ๋กญ๊ฒ ์ฃ ..? ์ด๋ ‡๊ฒŒ ํƒ€์ž…์— ์ œํ•œ์„ ๋‘์ง€ ์•Š๋Š” ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ Generic์ž…๋‹ˆ๋‹ค!

 

func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
   let tempA = a
   a = b
   b = tempA
}

 

์œ„์™€ ๊ฐ™์ด ๊บฝ์‡ (<>)๋ฅผ ์ด์šฉํ•ด์„œ ์•ˆ์— ํƒ€์ž… ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ด๋ฆ„(์œ„์˜ ์˜ˆ์ œ์—์„  T)์„ ์„ ์–ธํ•ด์ฃผ๋ฉด,
๊ทธ ๋’ค๋กœ ํ•ด๋‹น ์ด๋ฆ„(T)์„ ํƒ€์ž…์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์—ฌ๊ธฐ์„œ ์ด T๋ฅผ Type Parameter๋ผ๊ณ  ๋ถ€๋ฅด๋Š”๋ฐ, T๋ผ๋Š” ์ƒˆ๋กœ์šด ํ˜•์‹์ด ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ,
์‹ค์ œ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ํ•ด๋‹น ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ํƒ€์ž…์œผ๋กœ ๋Œ€์ฒด๋˜๋Š” placeholder์ด๊ธฐ ๋•Œ๋ฌธ์— Swift๋Š” "T"๋ผ๋Š” ์‹ค์ œ ํƒ€์ž…์„ ์ฐพ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— T๋ง๊ณ  ๋‹ค๋ฅธ ํƒ€์ž… ์ด๋ฆ„๋„ ๋‹ค ์‚ฌ์šฉ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค!

+ ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์€ ์–ด๋–ค ์ด๋ฆ„์ด๋“  ์ž์œ ๋กญ๊ฒŒ ์„ ์–ธ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ,
๋ณดํ†ต ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด T๋‚˜ V ๊ฐ™์€ ๋‹จ์ผ ๋ฌธ์ž, ํ˜น์€ Upper Camel Case๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค!

 

var someInt = 1
var anotherInt = 2
swapTwoValues(&someInt,  &anotherInt)          // ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ T๋Š” Int ํƒ€์ž…์œผ๋กœ ๊ฒฐ์ •๋จ
 
 
var someString = "Hi"
var anotherString = "Bye"
swapTwoValues(&someString, &anotherString)     // ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ T๋Š” String ํƒ€์ž…์œผ๋กœ

 

์œ„์™€ ๊ฐ™์ด ์ œ๋„ค๋ฆญ์œผ๋กœ ์„ ์–ธํ•œ ํ•จ์ˆ˜๋Š”
์ด๋ ‡๊ฒŒ ์‹ค์ œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ, Type Parameter์ธ T์˜ ํƒ€์ž…์ด ๊ฒฐ์ •๋ฉ๋‹ˆ๋‹ค!

 

swapTwoValues(&someInt, &anotherString)       // Cannot convert value of type 'String' to expected argument type 'Int'

 

๊ทธ๋Ÿฐ๋ฐ ๋งŒ์•ฝ ์œ„์™€ ๊ฐ™์ด ์„œ๋กœ ๋‹ค๋ฅธ ํƒ€์ž…์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
์™œ๋ƒํ•˜๋ฉด ์œ„์—์„œ ํ•จ์ˆ˜ ์ •์˜ ์‹œ ํŒŒ๋ผ๋ฏธํ„ฐ a์™€ b ๋‘˜๋‹ค ๊ฐ™์€ ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ์ธ T๋กœ ์„ ์–ธํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค!

์ด๋ ‡๊ฒŒ ์„œ๋กœ ๋‹ค๋ฅธ ํƒ€์ž…์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ•˜๋ฉด, ์ฒซ ๋ฒˆ์งธ someInt๋ฅผ ํ†ตํ•ด ํƒ€์ž…ํŒŒ๋ผ๋ฏธํ„ฐ T๊ฐ€ Int๋กœ ๊ฒฐ์ •๋๊ธฐ ๋•Œ๋ฌธ์—,
๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์ธ anotherString์˜ ํƒ€์ž…์ด Int๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉฐ ์—๋Ÿฌ๊ฐ€ ๋‚˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค!

 

func swapTwoValues<One, Two> { ... }

 

ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ,๋ฅผ ์ด์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ์„ ์–ธํ•ด์ค„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค!

์ด๋ ‡๊ฒŒ ์ œ๋„ค๋ฆญ ํ•จ์ˆ˜๋ฅผ ์ž˜ ์ด์šฉํ•˜๋ฉด ๋˜‘๊ฐ™์€ ๋‚ด์šฉ์˜ ํ•จ์ˆ˜๋ฅผ ์˜ค๋ฒ„๋กœ๋”ฉ ํ•  ํ•„์š”๊ฐ€ ์—†์–ด ์ฝ”๋“œ ์ค‘๋ณต์„ ํ”ผํ•˜๊ณ  ์œ ์—ฐํ•˜๊ฒŒ ์ฝ”๋“œ๋ฅผ ์งค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

Generic Type (์ œ๋„ค๋ฆญ ํƒ€์ž…)

์ œ๋„ค๋ฆญ์€ ํ•จ์ˆ˜์—๋งŒ ๊ฐ€๋Šฅํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ,
๊ตฌ์กฐ์ฒด, ํด๋ž˜์Šค, ์—ด๊ฑฐํ˜• ํƒ€์ž…์—๋„ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด๊ฒƒ์„ ์ œ๋„ค๋ฆญ ํƒ€์ž…(Generic Type) ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค!

๋งŒ์•ฝ Stack์„ ์ œ๋„ค๋ฆญ์œผ๋กœ ๋งŒ๋“ค๊ณ  ์‹ถ๋‹ค๋ฉด,

 

struct Stack<T> {
    let items: [T] = []
 
    mutating func push(_ item: T) { ... }
    mutating func pop() -> T { ... }
}

 

์ด๋ ‡๊ฒŒ ์ œ๋„ค๋ฆญ ํƒ€์ž…์œผ๋กœ Stack์„ ์„ ์–ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (ํด๋ž˜์Šค, ์—ด๊ฑฐํ˜• ๋˜ํ•œ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค)

์ œ๋„ค๋ฆญ ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ๋•Œ๋Š”

 

let stack1: Stack<Int> = .init()
let stack2 = Stack<Int>.init()

 

์ด๋ ‡๊ฒŒ ์„ ์–ธ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ <>๋ฅผ ํ†ตํ•ด ์–ด๋–ค ํƒ€์ž…์œผ๋กœ ์‚ฌ์šฉํ•  ๊ฒƒ์ธ์ง€๋ฅผ ๋ช…์‹œํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์š” ์„ ์–ธ ํ˜•์‹ ์–ด๋”˜๊ฐ€ ์ต์ˆ™ํ•œ๋ฐ..์–ด๋””์„œ ๋ดค๋ƒ๋ฉด..!!

 

var integers: Array<Int> = [Int]()

 

์ด๋Ÿฐ ์‹์œผ๋กœ ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•ด์ค„ ๋•Œ ํƒ€์ž…์„ ๋ช…์‹œํ•ด์ฃผ๊ณ  ์‹ถ๋‹ค๋ฉด ์ด๋ ‡๊ฒŒ <> ์•ˆ์— ๋„ฃ์–ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค!

 

 

์‚ฌ์‹ค์€ Swift์˜ Array๋Š” ์ œ๋„ค๋ฆญ ํƒ€์ž…์ด์—ˆ๋„ค์š”!

Generic์„ ์‚ฌ์šฉํ–ˆ๋‹ค๋Š” ๊ฒƒ์„ ์ธ์‹ ๋ชปํ–ˆ๋‹ค๊ณ  ํ•˜๋”๋ผ๋„ Language Guide ์ „์ฒด์—์„œ Generic์„ ์‚ฌ์šฉํ•ด์™”์Šต๋‹ˆ๋‹ค.

 

์ด๊ฒŒ ์š”๋Ÿฐ ๋œป์ด์—ˆ๋˜ ๊ฒƒ..!


[์ฐธ๊ณ  ์ž๋ฃŒ]

https://docs.swift.org/swift-book/LanguageGuide/Generics.html#//apple_ref/doc/uid/TP40014097-CH26-XID_283 

https://zeddios.tistory.com/226 

https://babbab2.tistory.com/136