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

์ดํŽ™ํ‹ฐ๋ธŒ ์ฝ”ํ‹€๋ฆฐ - 5์žฅ ๊ฐ์ฒด ์ƒ์„ฑ

by ์ฃผ๋ฐœ2 2025. 8. 15.
๋ฐ˜์‘ํ˜•


์•„์ดํ…œ 33. ์ƒ์„ฑ์ž ๋Œ€์‹  ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜์˜ ์žฅ์ 

  • ํ•จ์ˆ˜์— ์ด๋ฆ„์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ArrayList(3) vs ArrayList.withSize(3)
  • ์›ํ•˜๋Š” ํƒ€์ž…์˜ ๋ฆฌํ„ด์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ํ•„์š”๊ฐ€ ์—†๋‹ค.
    • ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ null ๋ฆฌํ„ด์„ ํ•˜๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
    • ex) createOrNull(), findByIdOrNull()
  • inline, reified๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
    • ์ธ๋ผ์ธ ํ•จ์ˆ˜๋กœ ๋งŒ๋“ค๋ฉด ์ปดํŒŒ์ผ ํ›„ ์ƒ์„ฑ๋˜๋Š” ๋ฐ”์ดํŠธ์ฝ”๋“œ์— ํ•จ์ˆ˜ ๋ณธ๋ฌธ์ด ๋“ค์–ด๊ฐ€์„œ ํ•จ์ˆ˜ ํ˜ธ์ถœ์˜ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์—†์–ด์ง„๋‹ค.
    • reified๋กœ ๋งŒ๋“ค๋ฉด ์ œ๋„ค๋ฆญ ํƒ€์ž…์˜ ์ •๋ณด๋ฅผ(Class Type) ๋Ÿฐํƒ€์ž„์—๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ฝ”ํ‹€๋ฆฐ์—์„œ ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜

class MyList<T>(
    val head: T,
    val tail: MyList<T>,
) {
    companion object {
        fun <T> of(vararg elements: T): MyList<T> { // ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜
            // ...
            
        }
    }
}

// ์ธํ„ฐํŽ˜์ด์Šค
class MyLinkedList<T>(
    val head: T,
    val tail: MyLinkedList<T>?
) : MyList<T> {
    // ...
}

interface MyList<T> {
    // ...

    companion object {
        fun <T> of(vararg elements: T): MyList<T> {
            // ...
        }
    }
}

val list = MyList.of(1, 2)

 

ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜ ๋„ค์ด๋ฐ

  • from: ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ•˜๋‚˜ ๋ฐ›๊ณ , ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค ํ•˜๋‚˜๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ํ•จ์ˆ˜
  • of: ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ๋ฐ›๊ณ , ์ด๋ฅผ ํ†ตํ•ฉํ•˜์—ฌ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜
  • instance(getInstance): ์‹ฑ๊ธ€ํ„ด์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜
  • get(), new() ...

 

ํ™•์žฅ ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜

  • ๊ฐ์ฒด์˜ ํ•จ์ˆ˜์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•  ๋•Œ, ์ด๋ฏธ ๋‹ค๋ฅธ companion ๊ฐ์ฒด๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ํ™•์žฅ ํ•จ์ˆ˜๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
// ์ด๋ฏธ companion object๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ
class Tool {
    companion object {
        fun createSmallTool(): Tool = Tool()
        fun createMediumTool(): Tool = Tool()
        
        // ์—ฌ๊ธฐ์— ์ƒˆ๋กœ์šด ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์ง€๋งŒ...
        // 1) ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๊ฑฐ๋‚˜
        // 2) ๋‹ค๋ฅธ ๋ชจ๋“ˆ/๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ํด๋ž˜์Šค์ธ ๊ฒฝ์šฐ
        // 3) ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ๋ฅผ ์œ„ํ•ด ๋ณ„๋„๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ
    }
}

// ํ™•์žฅ ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜
fun Tool.Companion.createBigTool(size: Int): Tool {
    return Tool().apply {
        // BigTool ํŠน๋ณ„ํ•œ ์ดˆ๊ธฐํ™” ๋กœ์ง
    }
}

 

 

ํ†ฑ๋ ˆ๋ฒจ ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜

  • ์ปฌ๋ ‰์…˜์—์„œ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“œ๋Š” ๋Œ€ํ‘œ์ ์ธ ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜ ์ค‘ listOf, setOf, mapOf ๋“ฑ์ด ์žˆ๋‹ค.
  • public ํ†ฑ๋ ˆ๋ฒจ ํ•จ์ˆ˜๋Š” ๋ชจ๋“  ๊ณณ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ , ๋„ค์ด๋ฐ ๋“ฑ์— ์žˆ์–ด์„œ ์‹ ์ค‘ํ•˜๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

expect๋Š” Kotlin Multiplatform์—์„œ ์‚ฌ์šฉ๋˜๋Š” ํ‚ค์›Œ๋“œ๋กœ, ํ”Œ๋žซํผ๋ณ„๋กœ ๋‹ค๋ฅธ ๊ตฌํ˜„์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜

๊ฐ ํ”Œ๋žซํผ๋ณ„ ์‹ค์ œ ๊ตฌํ˜„์€ actual ํ‚ค์›Œ๋“œ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

// ๊ณตํ†ต ์ฝ”๋“œ์—์„œ ์„ ์–ธ๋งŒ ํ•˜๊ณ  ๊ตฌํ˜„์€ ํ•˜์ง€ ์•Š์Œ
@SinceKotlin("1.9")
public expect fun <T> listOf(element: T): List<T>

// JVM ํ”Œ๋žซํผ ๊ตฌํ˜„
public actual fun <T> listOf(element: T): List<T> = 
    java.util.Collections.singletonList(element)

// JavaScript ํ”Œ๋žซํผ ๊ตฌํ˜„  
public actual fun <T> listOf(element: T): List<T> = 
    arrayOf(element).asList()

// Native ํ”Œ๋žซํผ ๊ตฌํ˜„
public actual fun <T> listOf(element: T): List<T> = 
    ImmutableList.of(element)

์•„์ดํ…œ 34. ๊ธฐ๋ณธ ์ƒ์„ฑ์ž์— ์ด๋ฆ„ ์žˆ๋Š” ์˜ต์…˜ ์•„๊ทœ๋จผํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

๊ฐ์ฒด๋ฅผ ์ •์˜ํ•˜๊ณ  ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ง€์ •ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ•์€ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž(primary constructor)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ

class User(val name: String, val surname: String)
val user = User(name = "A", surname = "B")

 

์ฝ”ํ‹€๋ฆฐ์—์„œ๋Š” ๋””ํดํŠธ ์•„๊ทœ๋จผํŠธ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

class Pizza(
    val size: String,
    val cheese: Int = 0,
    val olives: Int = 0,
    val bacon: Int = 0
)

val myFavorite = Pizza("L", olives = 3)
val myFavorite = Pizza("L", cheese = 1, olives = 3)

์•„์ดํ…œ 35. ๋ณต์žกํ•œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ DSL์„ ์ •์˜ํ•˜๋ผ

DSL(Domain Specific Language)์€ ๋ณต์žกํ•œ ๊ฐ์ฒด, ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฐ์ฒด๋“ค์„ ์ •์˜ํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค.

import javax.management.Query.div

// ์ฝ”ํ‹€๋ฆฐ DSL์„ ํ†ตํ•ด ํ‘œํ˜„ํ•œ HTML
body {
    div {
        a("https://kotlinlang.org") {
            target = ATarget.blank
            +"Main site"
        }
    }
    +"Some content"
}

// Main site
// Some content


// Android View DSL
verticalLayout {
    val name = editText()
    button("Say Hello") {
        onClick { toast("Hello, ${name.text}!") }
    }
}


// Ktor API
fun Routing.api() {
    route("news") {
        get {
            val newsData = NewsUseCase.getAcceptedNews()
            call.respond(newsData)
        }
        get("propositions") {
            requireSecret()
            ...
        }
    }
}


// kotest
class SearchTest : BehaviorSpec(
    {
        given("SearchTest") {
            `when`("๋žœ๋ค์œผ๋กœ ์…”ํ”Œํ•  ๋ณ€ํ˜ธ์‚ฌ๊ฐ€ 8๋ช…๋ณด๋‹ค ์ ์€ ๊ฒฝ์šฐ,") {
                then("์…”ํ”Œ๋ง ์—†์ด ๋ชจ๋“  ๋ณ€ํ˜ธ์‚ฌ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.") {
                    val sut = List(5) { LawyerSearchFixture.create(lawyerId = it.toLong()) }

                    val actual = LawyerSearch.getShuffledLawyerSearches(sut)

                    assertSoftly {
                        actual.size shouldBe sut.size
                        actual shouldBe sut
                    }
                }
            }
        }
    },
)

 

์‚ฌ์šฉ์ž ์ •์˜ DSL

๋ฆฌ์‹œ๋ฒ„๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜ ํƒ€์ž…์— ๋Œ€ํ•œ ๊ฐœ๋…์„ ์ดํ•ดํ•ด์•ผ ํ•˜๋Š”๋ฐ, ํ•จ์ˆ˜ ํƒ€์ž…์€ ํ•จ์ˆ˜๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํƒ€์ž…

// predicate์— ํ•จ์ˆ˜ ํƒ€์ž…์ด ํ™œ์šฉ
public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
    return filterTo(ArrayList<T>(), predicate)
}

 

ํ•จ์ˆ˜ ํƒ€์ž…์˜ ์˜ˆ์‹œ

  • () → Unit : ์•„๊ทœ๋จผํŠธ๋ฅผ ๊ฐ–์ง€ ์•Š๊ณ , Unit ๋ฐ˜ํ™˜
  • (Int) → Unit
  • (Int, Int) → Int

 

ํ•จ์ˆ˜ ํƒ€์ž…์„ ๋งŒ๋“œ๋Š” ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ•

  • ๋žŒ๋‹ค ํ‘œํ˜„์‹, ์ต๋ช… ํ•จ์ˆ˜, ํ•จ์ˆ˜ ๋ ˆํผ๋Ÿฐ์Šค
fun plus(a: Int, b: Int) = a + b

// plus() ์™€ ์œ ์‚ฌ ํ•จ์ˆ˜
val plus1: (Int, Int) -> Int = { a, b -> a + b }
val plus2: (Int, Int) -> Int = fun(a, b) = a + b
val plus3: (Int, Int) -> Int = ::plus
val plus4: { a: Int, b: Int -> a + b }

 

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€