{"componentChunkName":"component---src-containers-post-index-tsx","path":"/backend/kotlin-in-action/10장-고차함수-람다를_파라미터와_반환값으로_사용/","result":{"pageContext":{"next":{"id":"dd1d7589-298b-5305-9cd3-3de0eb0cc3f7","html":"<p>코틀린은 어떤 언어 기능과 미리 정해진 이름의 함수를 연결해주는 기법인 관례에 의존한다.</p>\n<h2 id=\"-91-산술-연산자를-오버로드해서-임의의-클래스에-대한-연산을-더-편리하게-만들기\" style=\"position:relative;\"><a href=\"#-91-%EC%82%B0%EC%88%A0-%EC%97%B0%EC%82%B0%EC%9E%90%EB%A5%BC-%EC%98%A4%EB%B2%84%EB%A1%9C%EB%93%9C%ED%95%B4%EC%84%9C-%EC%9E%84%EC%9D%98%EC%9D%98-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%97%90-%EB%8C%80%ED%95%9C-%EC%97%B0%EC%82%B0%EC%9D%84-%EB%8D%94-%ED%8E%B8%EB%A6%AC%ED%95%98%EA%B2%8C-%EB%A7%8C%EB%93%A4%EA%B8%B0\" aria-label=\" 91 산술 연산자를 오버로드해서 임의의 클래스에 대한 연산을 더 편리하게 만들기 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 9.1 산술 연산자를 오버로드해서 임의의 클래스에 대한 연산을 더 편리하게 만들기</h2>\n<h3 id=\"-911-plus-times-divide-등-이항-산술-연산-오버로딩\" style=\"position:relative;\"><a href=\"#-911-plus-times-divide-%EB%93%B1-%EC%9D%B4%ED%95%AD-%EC%82%B0%EC%88%A0-%EC%97%B0%EC%82%B0-%EC%98%A4%EB%B2%84%EB%A1%9C%EB%94%A9\" aria-label=\" 911 plus times divide 등 이항 산술 연산 오버로딩 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 9.1.1 plus, times, divide 등: 이항 산술 연산 오버로딩</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">data class Point(val x: Int, val y: Int) {\n    operator fun plus(other: Point): Point {\n        return Point(x + other.x, y + other.y)\n    }\n}\n\nfun main() {\n    val p1 = Point(10, 20)\n    val p2 = Point(30, 40)\n    println(p1 + p2) // + 기호를 쓰면 plus 함수 호출\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>plus 함수 앞에 operator 키워드를 붙여야 한다.</li>\n<li>연산자를 확장 함수로 정의할 수도 있다.</li>\n</ul>\n<table>\n<thead>\n<tr>\n<th>표현식</th>\n<th>함수 이름</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>a + b</td>\n<td>plus</td>\n</tr>\n<tr>\n<td>a - b</td>\n<td>minus</td>\n</tr>\n<tr>\n<td>a * b</td>\n<td>times</td>\n</tr>\n<tr>\n<td>a / b</td>\n<td>div</td>\n</tr>\n<tr>\n<td>a % b</td>\n<td>mod</td>\n</tr>\n</tbody>\n</table>\n<ul>\n<li>연산자 우선순위는 표준 숫자 타입에 대한 연산자 우선순위와 같다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">operator fun Point.times(scale: Double): Point {\n    return Point((x * scale).toInt(), (y * scale).toInt())\n}\n\nfun main() {\n    val p = Point(10, 20)\n    println(p * 1.5)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>연산자를 정의할 때 두 피연산자가 같은 타입일 필요는 없다.</li>\n<li>자동으로 교환법칙을 지원하지 않는다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">operator fun Char.times(count: Int): String {\n    return toString().repeat(count)\n}\n\nfun main() {\n    println(&#39;a&#39; * 3)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>연산자 함수의 반환 타입이 꼭 두 피연산자 중 하나와 일치해야만 하는 것도 아니다.</li>\n</ul>\n<h3 id=\"-912-연산을-적용한-다음에-그-결과를-바로-대입-복합-대입-연산자-오버로딩\" style=\"position:relative;\"><a href=\"#-912-%EC%97%B0%EC%82%B0%EC%9D%84-%EC%A0%81%EC%9A%A9%ED%95%9C-%EB%8B%A4%EC%9D%8C%EC%97%90-%EA%B7%B8-%EA%B2%B0%EA%B3%BC%EB%A5%BC-%EB%B0%94%EB%A1%9C-%EB%8C%80%EC%9E%85-%EB%B3%B5%ED%95%A9-%EB%8C%80%EC%9E%85-%EC%97%B0%EC%82%B0%EC%9E%90-%EC%98%A4%EB%B2%84%EB%A1%9C%EB%94%A9\" aria-label=\" 912 연산을 적용한 다음에 그 결과를 바로 대입 복합 대입 연산자 오버로딩 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 9.1.2 연산을 적용한 다음에 그 결과를 바로 대입: 복합 대입 연산자 오버로딩</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    var point = Point(1, 2)\n    point += Point(3, 4)\n    println(point)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>plus와 같은 연산자를 오버로딩하면 복합 대입 연산자를 자동으로 지원한다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">operator fun &lt;T&gt; MutableCollection&lt;T&gt;.plusAssign(element: T) {\n    this.add(element)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>어떤 클래스가 plus, plusAssign을 모두 정의하고 +=을 사용하면 오류를 보고한다.</li>\n<li>코틀린 표준 라이브러리는 컬렉션에 대해 2가지 접근 방법을 제공\n<ul>\n<li>+,-는 항상 새로운 컬렉션 반환</li>\n<li>+=, -= 연산자는 항상 변경 가능한 컬렉션에 작용해 메모리에 있는 객체 상태를 변화</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"-913-피연산자가-1개뿐인-연산자-단항-연산자-오버로딩\" style=\"position:relative;\"><a href=\"#-913-%ED%94%BC%EC%97%B0%EC%82%B0%EC%9E%90%EA%B0%80-1%EA%B0%9C%EB%BF%90%EC%9D%B8-%EC%97%B0%EC%82%B0%EC%9E%90-%EB%8B%A8%ED%95%AD-%EC%97%B0%EC%82%B0%EC%9E%90-%EC%98%A4%EB%B2%84%EB%A1%9C%EB%94%A9\" aria-label=\" 913 피연산자가 1개뿐인 연산자 단항 연산자 오버로딩 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 9.1.3 피연산자가 1개뿐인 연산자: 단항 연산자 오버로딩</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">operator fun Point.unaryMinus(): Point {\n    return Point(-x, -y)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>단항 연산자를 오버로딩하기 위해 사용하는 함수는 인자를 취하지 않는다.</li>\n</ul>\n<table>\n<thead>\n<tr>\n<th>표현식</th>\n<th>함수 이름</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>+a</td>\n<td>unaryPlus</td>\n</tr>\n<tr>\n<td>-a</td>\n<td>unaryMinus</td>\n</tr>\n<tr>\n<td>!a</td>\n<td>not</td>\n</tr>\n<tr>\n<td>a++, ++a</td>\n<td>inc</td>\n</tr>\n<tr>\n<td>a-- , --a</td>\n<td>dec</td>\n</tr>\n</tbody>\n</table>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    var bd = BigDecimal.ZERO\n    println(bd++) // 후위 증가 연산자는 println이 실행된 다음에 값 증가\n    println(bd)\n    println(++bd) // 전위 증가 연산자는 println이 실행되기 전에 값 증가\n}</code>\n        </deckgo-highlight-code>\n<h2 id=\"-92-비교-연산자를-오버로딩해서-객체들-사이의-관계를-쉽게-검사\" style=\"position:relative;\"><a href=\"#-92-%EB%B9%84%EA%B5%90-%EC%97%B0%EC%82%B0%EC%9E%90%EB%A5%BC-%EC%98%A4%EB%B2%84%EB%A1%9C%EB%94%A9%ED%95%B4%EC%84%9C-%EA%B0%9D%EC%B2%B4%EB%93%A4-%EC%82%AC%EC%9D%B4%EC%9D%98-%EA%B4%80%EA%B3%84%EB%A5%BC-%EC%89%BD%EA%B2%8C-%EA%B2%80%EC%82%AC\" aria-label=\" 92 비교 연산자를 오버로딩해서 객체들 사이의 관계를 쉽게 검사 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 9.2 비교 연산자를 오버로딩해서 객체들 사이의 관계를 쉽게 검사</h2>\n<h3 id=\"-921-동등성-연산자-equals\" style=\"position:relative;\"><a href=\"#-921-%EB%8F%99%EB%93%B1%EC%84%B1-%EC%97%B0%EC%82%B0%EC%9E%90-equals\" aria-label=\" 921 동등성 연산자 equals permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 9.2.1 동등성 연산자: equals</h3>\n<ul>\n<li>!= 연산자를 사용하는 식도 equals 호출로 컴파일 된다.</li>\n<li>null 검사도 한다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Point(val x: Int, val y: Int) {\n    override fun equals(other: Any?): Boolean {\n        if (other === this) return true\n        if (other !is Point) return false\n        return other.x == x &amp;&amp; other.y == y\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>동등성 비교 연산자(===)는 자바 == 연산자와 같다.\n<ul>\n<li>자신의 두 피연산자가 서로 같은 객체ㅡㄹ 가리키는지 비교한다.</li>\n</ul>\n</li>\n<li>===를 오버로딩할 수는 없다.</li>\n</ul>\n<h3 id=\"-922-순서-연산자-compareto----\" style=\"position:relative;\"><a href=\"#-922-%EC%88%9C%EC%84%9C-%EC%97%B0%EC%82%B0%EC%9E%90-compareto----\" aria-label=\" 922 순서 연산자 compareto     permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 9.2.2 순서 연산자: compareTo (&#x3C;, >, &#x3C;=, >=)</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Person(val firstName: String, val lastName: String) : Comparable&lt;Person&gt; {\n    override fun compareTo(other: Person): Int {\n        return compareValuesBy(this, other, Person::lastName, Person::firstName)\n    }\n}\n\nfun main() {\n    val p1 = Person(&quot;Alice&quot;, &quot;Smith&quot;)\n    val p2 = Person(&quot;Bob&quot;, &quot;Johnson&quot;)\n    println(p1 &lt; p2)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>비교 연산자를 제공한다.</li>\n<li><code>compareValuesBy</code>는 두 객체와 여러 비교 함수를 인자로 받는다.\n<ul>\n<li>첫 번째 비교 함수에 두 객체를 넘겨 두 객체가 같지 않다는 결과가 나오면 그 결괏값을 즉시 반환</li>\n</ul>\n</li>\n<li>비교 연산자를 자바 클래스에 대해 사용하기 위해 특별히 확장 메서드를 만들거나 할 필요는 없다.</li>\n</ul>\n<h2 id=\"-93-컬렉션과-범위에-대해-쓸-수-있는-관례\" style=\"position:relative;\"><a href=\"#-93-%EC%BB%AC%EB%A0%89%EC%85%98%EA%B3%BC-%EB%B2%94%EC%9C%84%EC%97%90-%EB%8C%80%ED%95%B4-%EC%93%B8-%EC%88%98-%EC%9E%88%EB%8A%94-%EA%B4%80%EB%A1%80\" aria-label=\" 93 컬렉션과 범위에 대해 쓸 수 있는 관례 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 9.3 컬렉션과 범위에 대해 쓸 수 있는 관례</h2>\n<h3 id=\"-931-인덱스로-원소-접근-get과-set\" style=\"position:relative;\"><a href=\"#-931-%EC%9D%B8%EB%8D%B1%EC%8A%A4%EB%A1%9C-%EC%9B%90%EC%86%8C-%EC%A0%91%EA%B7%BC-get%EA%B3%BC-set\" aria-label=\" 931 인덱스로 원소 접근 get과 set permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 9.3.1 인덱스로 원소 접근: get과 set</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">operator fun Point.get(index: Int): Int {\n    return when (index) {\n        0 -&gt; x\n        1 -&gt; y\n        else -&gt;\n            throw IndexOutOfBoundsException(&quot;Invalid coordinate $index&quot;)\n    }\n}\n\nfun main() {\n    val p = Point(10, 20)\n    println(p[1])\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>get 메서드의 파라미터로 Int가 아닌 타입도 사용할 수 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">data class MutablePoint(var x: Int, var y: Int)\n\noperator fun MutablePoint.set(index: Int, value: Int) {\n    when (index) {\n        0 -&gt; x = value\n        1 -&gt; y = value\n        else -&gt;\n            throw IndexOutOfBoundsException(&quot;Invalid coordinate $index&quot;)\n    }\n}\n\nfun main() {\n    val p = MutablePoint(10, 20)\n    p[1] = 42\n    println(p)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>set도 관례로 표현할 수 있다.</li>\n</ul>\n<h3 id=\"-932-어떤-객체가-컬렉션에-들어있는지-검사-in-관레\" style=\"position:relative;\"><a href=\"#-932-%EC%96%B4%EB%96%A4-%EA%B0%9D%EC%B2%B4%EA%B0%80-%EC%BB%AC%EB%A0%89%EC%85%98%EC%97%90-%EB%93%A4%EC%96%B4%EC%9E%88%EB%8A%94%EC%A7%80-%EA%B2%80%EC%82%AC-in-%EA%B4%80%EB%A0%88\" aria-label=\" 932 어떤 객체가 컬렉션에 들어있는지 검사 in 관레 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 9.3.2 어떤 객체가 컬렉션에 들어있는지 검사: in 관레</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">data class Rectangle(val upperLeft: Point, val lowerRight: Point)\n\noperator fun Rectangle.contains(p: Point): Boolean {\n    return p.x in upperLeft.x..&lt;lowerRight.x &amp;&amp;\n            p.y in upperLeft.y..&lt;lowerRight.y // 열린 범위\n}\n\nfun main() {\n    val rect = Rectangle(Point(10, 20), Point(50, 50))\n    println(Point(20, 30) in rect)\n    println(Point(5, 5) in rect)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>..&#x3C; 연산자를 쓰면 열린 범위를 만들 수 있다.</li>\n<li>in 함수는 contains 메서드의 수신 객체가 되고 in의 왼쪽에 있는 객체는 contains 메서드에 인자로 전달된다.</li>\n</ul>\n<h3 id=\"-933-객체로부터-범위-만들기-rangeto와-rangeuntil-관레\" style=\"position:relative;\"><a href=\"#-933-%EA%B0%9D%EC%B2%B4%EB%A1%9C%EB%B6%80%ED%84%B0-%EB%B2%94%EC%9C%84-%EB%A7%8C%EB%93%A4%EA%B8%B0-rangeto%EC%99%80-rangeuntil-%EA%B4%80%EB%A0%88\" aria-label=\" 933 객체로부터 범위 만들기 rangeto와 rangeuntil 관레 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 9.3.3 객체로부터 범위 만들기: rangeTo와 rangeUntil 관레</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">operator fun &lt;T: Comparable&lt;T&gt;&gt; T.rangeTo(other: T): ClosedRange&lt;T&gt;</code>\n        </deckgo-highlight-code>\n<ul>\n<li>코틀린 표준 라이브러리에는 모든 Comparable 객체에 대해 적용 가능한 rangeTo 함수가 들어있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val now = LocalDate.now()\n    val vacation = now..now.plusDays(10)\n    println(now.plusWeeks(1) in vacation)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>now..now.plusDays(10)</code> 식은 컴파일러에 의해 <code>now.rangeTo(now.plusDays(10))</code>으로 변환된다.</li>\n<li>rangeTo 연산자는 다른 산술 연산자보다 우선순위가 낮다.\n<ul>\n<li>혼동을 피하기 위해 괄호를 쓰자!</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val n = 9\n    (0..n).forEach { println(it) }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>범위의 메서드를 호출하려면 범위를 괄호로 둘러싸야 한다.</li>\n<li>rangeUntil 연산자(..&#x3C;)>=는 열린 범위를 만든다.</li>\n</ul>\n<h3 id=\"-934-자신의-타입에-대해-루프-수행-iterator-관례\" style=\"position:relative;\"><a href=\"#-934-%EC%9E%90%EC%8B%A0%EC%9D%98-%ED%83%80%EC%9E%85%EC%97%90-%EB%8C%80%ED%95%B4-%EB%A3%A8%ED%94%84-%EC%88%98%ED%96%89-iterator-%EA%B4%80%EB%A1%80\" aria-label=\" 934 자신의 타입에 대해 루프 수행 iterator 관례 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 9.3.4 자신의 타입에 대해 루프 수행: iterator 관례</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">operator fun CharSequence.iterator(): CharIterator</code>\n        </deckgo-highlight-code>\n<ul>\n<li>이 라이브러리 함수는 문자열을 이터레이션할 수 있게 해준다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">operator fun ClosedRange&lt;LocalDate&gt;.iterator(): Iterator&lt;LocalDate&gt; =\n    object : Iterator&lt;LocalDate&gt; {\n        var current = start\n        override fun hasNext(): Boolean =\n            current &lt;= endInclusive\n        override fun next(): LocalDate {\n            val thisDate = current\n            current = current.plusDays(1)\n            return thisDate\n        }\n    }\n\nfun main() {\n    val newYear = LocalDate.ofYearDay(2042, 1)\n    val daysOff = newYear.minusDays(1)..newYear\n    for (dayOff in daysOff) {\n        println(dayOff)\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>ClosedRange&#x3C;LocalDate></code>에 대한 확장 함수 iterator를 정의했기 때문에 LocalDate의 범위 객체를 for 루프에 사용할 수 있다.</li>\n</ul>\n<h2 id=\"-94-component-함수를-사용해-구조-분해-선언-제공\" style=\"position:relative;\"><a href=\"#-94-component-%ED%95%A8%EC%88%98%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%B4-%EA%B5%AC%EC%A1%B0-%EB%B6%84%ED%95%B4-%EC%84%A0%EC%96%B8-%EC%A0%9C%EA%B3%B5\" aria-label=\" 94 component 함수를 사용해 구조 분해 선언 제공 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 9.4 component 함수를 사용해 구조 분해 선언 제공</h2>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val p = Point(10, 20)\n    val (x, y) = p\n    println(x)\n    println(y)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>구조 분해 선언은 일반 변수 선언과 비슷해 보인다.</li>\n<li>내부에서 구조 분해 선언의 각 변수를 초기화하고자 componentN이라는 함수를 호출한다.\n<ul>\n<li>N은 구조 분해 선언에 있는 변수 위치에 따라 붙는 번호</li>\n</ul>\n</li>\n<li>data class의 주 생성자에 들어있는 프로퍼티에 대해서는 컴파일러가 자동으로 componentN 함수를 만들어준다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">data class NameComponents(val name: String, val extension: String)\n\nfun splitFileName(fullName: String): NameComponents {\n    val result = fullName.split(&#39;.&#39;, limit = 2)\n    return NameComponents(result[0], result[1])\n}\n\nfun main() {\n    val (name, ext) = splitFileName(&quot;example.kt&quot;)\n    println(name)\n    println(ext)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>구조 분해 선언을 사용해 여러 값 반환이 가능하다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">data class NameComponents(val name: String, val extension: String)\n\nfun splitFileName(fullName: String): NameComponents {\n    val (name, extension) = fullName.split(&#39;.&#39;, limit = 2)\n    return NameComponents(name, extension)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>컬렉션에 대해 구조 분해 선언 사용이 가능하다.</li>\n</ul>\n<h3 id=\"-941-구조-분해-선언과-루프\" style=\"position:relative;\"><a href=\"#-941-%EA%B5%AC%EC%A1%B0-%EB%B6%84%ED%95%B4-%EC%84%A0%EC%96%B8%EA%B3%BC-%EB%A3%A8%ED%94%84\" aria-label=\" 941 구조 분해 선언과 루프 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 9.4.1 구조 분해 선언과 루프</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun printEntries(map: Map&lt;String, String&gt;) {\n    for ((key, value) in map) {\n        println(&quot;$key -&gt; $value&quot;)\n    }\n}\n\nfun main() {\n    val map = mapOf(&quot;Oracle&quot; to &quot;Java&quot;, &quot;JetBrains&quot; to &quot;Kotlin&quot;)\n    printEntries(map)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>맵에 대한 확장 함수로 iterator가 들어있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">    map.forEach { (key, value) -&gt; println(&quot;$key -&gt; $value&quot;) }</code>\n        </deckgo-highlight-code>\n<ul>\n<li>람다가 구조 분해 선언을 쓸 수 있다.</li>\n</ul>\n<h3 id=\"-942-_-문자를-사용해-구조-분해-값-무시\" style=\"position:relative;\"><a href=\"#-942-_-%EB%AC%B8%EC%9E%90%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%B4-%EA%B5%AC%EC%A1%B0-%EB%B6%84%ED%95%B4-%EA%B0%92-%EB%AC%B4%EC%8B%9C\" aria-label=\" 942 _ 문자를 사용해 구조 분해 값 무시 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 9.4.2 _ 문자를 사용해 구조 분해 값 무시</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">data class Person(val firstName: String, val lastName: String, val age: Int, val city: String)\n\nfun introducePerson(p: Person) {\n    val (firstName, lastName, age, city) = p\n    println(&quot;This is $firstName, aged $age.&quot;)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>전체 객체를 구조 분해해야만 하는 것은 아니기 때문에 구조 분해 선언에서 뒤쪽의 구조 분해 선언을 제거할 수는 잇다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">    val (firstName, lastName, age) = p</code>\n        </deckgo-highlight-code>\n<ul>\n<li>lastName을 그냥 없앨 수는 없다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun introducePerson(p: Person) {\n    val (firstName, _, age) = p\n    println(&quot;This is $firstName, aged $age.&quot;)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>_</code> 를 쓰면 컴포넌트를 무시하고 구조 분해 선언이 가능하다.</li>\n</ul>\n<h2 id=\"-95-프로퍼티-접근자-로직-재활용-위임-프로퍼티\" style=\"position:relative;\"><a href=\"#-95-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0-%EC%A0%91%EA%B7%BC%EC%9E%90-%EB%A1%9C%EC%A7%81-%EC%9E%AC%ED%99%9C%EC%9A%A9-%EC%9C%84%EC%9E%84-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0\" aria-label=\" 95 프로퍼티 접근자 로직 재활용 위임 프로퍼티 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 9.5 프로퍼티 접근자 로직 재활용: 위임 프로퍼티</h2>\n<h3 id=\"-951-위임-프로퍼티의-기본-문법과-내부-동작\" style=\"position:relative;\"><a href=\"#-951-%EC%9C%84%EC%9E%84-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95%EA%B3%BC-%EB%82%B4%EB%B6%80-%EB%8F%99%EC%9E%91\" aria-label=\" 951 위임 프로퍼티의 기본 문법과 내부 동작 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 9.5.1 위임 프로퍼티의 기본 문법과 내부 동작</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Foo {\n    var p = Type by Delegate()\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>p 프로퍼티는 접근자 로직을 다른 객체에 위임한다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Foo {\n    private val delegate = Delegate()\n    \n    var p: Type\n        set(value: Type) = delegate.setValue(/**/, value)\n        get() = delegate.getValue(/**/)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>프로퍼티 위임 관례에 따라 Delegate 클래스는 get, set을 제공해야한다.</li>\n<li>by 키워드는 프로퍼티와 위임객체를 연결한다.</li>\n</ul>\n<h3 id=\"-952-위임-프로퍼티-사용-by-lazy를-사용한-지연-초기화\" style=\"position:relative;\"><a href=\"#-952-%EC%9C%84%EC%9E%84-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0-%EC%82%AC%EC%9A%A9-by-lazy%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%9C-%EC%A7%80%EC%97%B0-%EC%B4%88%EA%B8%B0%ED%99%94\" aria-label=\" 952 위임 프로퍼티 사용 by lazy를 사용한 지연 초기화 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 9.5.2 위임 프로퍼티 사용: by lazy()를 사용한 지연 초기화</h3>\n<ul>\n<li>지연 초기화는 객체의 일부분을 초기화하지 않고 남겨뒀다가 실제로 그 부분의 값이 필요할 경우 초기화할 때 쓰이는 패턴</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Person(val name: String) {\n    private var _emails: List&lt;String&gt;? = null\n\n    val emails: List&lt;String&gt;\n        get() {\n            if (_emails == null) {\n                _emails = loadEamils(this)\n            }\n            return _emails!!\n        }\n}\n\n\nfun main() {\n    val p = Person(&quot;Alice&quot;)\n    p.emails\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>뒷받침하는 프로퍼티 기법 사용</li>\n<li>클래스 같은 개념을 표헌하는 프로퍼티가 2개 있을 때 비공개 프로퍼티 앞에 밑줄을 붙이며, 공개 프로퍼티에는 아무것도 붙이지 않는다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Person(val name: String) {\n    val emails by lazy { loadEmails(this) }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>위임 프로퍼티를 사용하면 훨씬 간단해진다.</li>\n<li>lazy 함수는 기본적으로 스레드 안전하다.</li>\n</ul>\n<h3 id=\"-953-위임-프로퍼티-구현\" style=\"position:relative;\"><a href=\"#-953-%EC%9C%84%EC%9E%84-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0-%EA%B5%AC%ED%98%84\" aria-label=\" 953 위임 프로퍼티 구현 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 9.5.3 위임 프로퍼티 구현</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun interface Observer {\n    fun onChange(name: String, oldValue: Any?, newValue: Any?)\n}\n\nopen class Observable {\n    val observers = mutableListOf&lt;Observer&gt;()\n    fun notifyObservers(propName: String, oldValue: Any?, newValue: Any?) {\n        for (obs in observers) {\n            obs.onChange(propName, oldValue, newValue)\n        }\n    }\n}\n\nclass Person(val name: String, age: Int, salary: Int) : Observable() {\n    var age: Int = age\n        set(newValue) {\n            val oldValue = field\n            field = newValue\n            notifyObservers(&quot;age&quot;, oldValue, newValue)\n        }\n    var salary: Int = salary\n        set(newValue) {\n            val oldValue = field\n            field = newValue\n            notifyObservers(&quot;salary&quot;, oldValue, newValue)\n        }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>field 키워드를 사용해 age와 salary 프로퍼티를 뒷받침하는 필드에 접근하는 방법을 보여준다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class ObservableProperty(val propName: String, var propValue: Int, val observable: Observable) {\n    fun getValue(): Int = propValue\n    fun setValue(newValue: Int) {\n        val oldValue = propValue\n        propValue = newValue\n        observable.notifyObservers(propName, oldValue, newValue)\n    }\n}\n\nclass Person(val name: String, age: Int, salary: Int) : Observable() {\n    val _age = ObservableProperty(&quot;age&quot;, age, this)\n    var age: Int\n        get() = _age.getValue()\n        set(value) {\n            _age.setValue(value)\n        }\n    val _salary = ObservableProperty(&quot;salary&quot;, salary, this)\n    var salary: Int\n        get() = _salary.getValue()\n        set(value) {\n            _salary.setValue(value)\n        }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>프로퍼티 값을 저장하고 그 값이 바뀌면 자동으로 변경 통지를 전달해주는 클래스를 만들었다.</li>\n<li>위임 프로퍼티를 사용하면 더 간단해진다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class ObservableProperty(var propValue: Int, val observable: Observable) {\n    operator fun getValue(thisRef: Any?, prop: KProperty&lt;*&gt;): Int = propValue\n    operator fun setValue(thisRef: Any?, prop: KProperty&lt;*&gt;, newValue: Int) {\n        val oldValue = propValue\n        propValue = newValue\n        observable.notifyObservers(prop.name, oldValue, newValue)\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>operator 변경자가 붙는다.</li>\n<li>KProperty 타입의 객체를 사용해 프로퍼티 표현</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Person(val name: String, age: Int, salary: Int) : Observable() {\n    val age by ObservableProperty(age, this)\n    var salary by ObservableProperty(salary, this)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>여러 작업을 컴파일러가 자동으로 처리해준다.</li>\n<li>by의 오른쪽에 있는 식이 꼭 새 인스턴스를 만들 필요는 없다.</li>\n</ul>\n<h3 id=\"-954-위임-프로퍼티는-커스텀-접근자가-있는-감춰진-프로퍼티로-변환된다\" style=\"position:relative;\"><a href=\"#-954-%EC%9C%84%EC%9E%84-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0%EB%8A%94-%EC%BB%A4%EC%8A%A4%ED%85%80-%EC%A0%91%EA%B7%BC%EC%9E%90%EA%B0%80-%EC%9E%88%EB%8A%94-%EA%B0%90%EC%B6%B0%EC%A7%84-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0%EB%A1%9C-%EB%B3%80%ED%99%98%EB%90%9C%EB%8B%A4\" aria-label=\" 954 위임 프로퍼티는 커스텀 접근자가 있는 감춰진 프로퍼티로 변환된다 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 9.5.4 위임 프로퍼티는 커스텀 접근자가 있는 감춰진 프로퍼티로 변환된다</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class C {\n    private val &lt;delegate&gt; = MyDelegate()\n    \n    var prop: Type\n        get() = &lt;delegate&gt;.getValue(this, &lt;property&gt;)\n        set(value: Type) = &lt;delegate&gt;.setValue(this, &lt;property&gt;, value)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>컴파일러는 모든 프로퍼티 접근자 안에 getValue, setValue 호출 코드를 생성해준다.</li>\n<li>프로퍼티 값이 저장될 장소를 바꿀 수도 있고 프로퍼티를 읽거나 쓸 때 벌어질 일을 변경할 수도 있다.</li>\n</ul>\n<h3 id=\"-955-맵에-위임해서-동적으로-애트리뷰트-접근\" style=\"position:relative;\"><a href=\"#-955-%EB%A7%B5%EC%97%90-%EC%9C%84%EC%9E%84%ED%95%B4%EC%84%9C-%EB%8F%99%EC%A0%81%EC%9C%BC%EB%A1%9C-%EC%95%A0%ED%8A%B8%EB%A6%AC%EB%B7%B0%ED%8A%B8-%EC%A0%91%EA%B7%BC\" aria-label=\" 955 맵에 위임해서 동적으로 애트리뷰트 접근 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 9.5.5 맵에 위임해서 동적으로 애트리뷰트 접근</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Person {\n    private val _attributes = mutableMapOf&lt;String, String&gt;()\n\n    fun setAttribute(attrName: String, value: String) {\n        _attributes[attrName] = value\n    }\n\n    var name: String\n        get() = _attributes[&quot;name&quot;]!!\n        set(value) {\n            _attributes[&quot;name&quot;] = value\n        }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>위임 프로퍼티를 활용하도록 변경하는 것은 아주 쉽다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Person {\n    private val _attributes = mutableMapOf&lt;String, String&gt;()\n\n    fun setAttribute(attrName: String, value: String) {\n        _attributes[attrName] = value\n    }\n\n    var name: String by _attributes\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>Map에 대해 getValue, setValue 확장 함수를 제공하기에 동작함.</li>\n<li>getValue에서 맵에 프로퍼티 값을 저장할 때는 자동으로 프로퍼티 이름을 키로 활용</li>\n</ul>\n<h3 id=\"-956-실전-프레임워크가-위임-프로퍼티를-활용하는-방법\" style=\"position:relative;\"><a href=\"#-956-%EC%8B%A4%EC%A0%84-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC%EA%B0%80-%EC%9C%84%EC%9E%84-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95\" aria-label=\" 956 실전 프레임워크가 위임 프로퍼티를 활용하는 방법 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 9.5.6 실전 프레임워크가 위임 프로퍼티를 활용하는 방법</h3>\n<ul>\n<li>위임 프로퍼티는 프로퍼티의 접근 로직을 재사용 가능하게 만들어, 코드의 중복을 줄이고 유지보수성을 향상시킨다.</li>\n<li>프레임워크나 라이브러리에서 공통된 프로퍼티 동작을 캡슐화하여, 사용자 코드의 간결함과 일관성을 유지할 수 있다.</li>\n</ul>","excerpt":"코틀린은 어떤 언어 기능과 미리 정해진 이름의 함수를 연결해주는 기법인 관례에 의존한다. 📖 9.1 산술 연산자를 오버로드해서 임의의 클래스에 대한 연산을 더 편리하게 만들기 🔖 9.1.1 plus, times, divide 등: 이항 산술 연산 오버로딩 plus 함수 앞에 operator 키워드를 붙여야 한다. 연산자를 확장 함수로 정의할 수도 있다. 표현식 함수 이름 a + b plus a - b minus a * b times a / b div a % b mod…","fields":{"slug":"/backend/kotlin-in-action/9장-연산자_오버로딩과_다른_관례/"},"frontmatter":{"title":"Kotlin in Action - 9장 연산자 오버로딩과 다른 관례","thumbnail":{"childImageSharp":{"fluid":{"src":"/static/f7f7ddfa31d1614405dc5af1487b9ec4/9c94d/kotlin-in-action.png"}}},"draft":false,"category":"Back-End","tags":["Kotlin"],"date":"April 27, 2025"}},"previous":{"id":"b5f5340f-f158-5b1d-aff9-1d7991c14962","html":"<h2 id=\"-111-타입-인자를-받는-타입-만들기-제네릭-타입-파라미터\" style=\"position:relative;\"><a href=\"#-111-%ED%83%80%EC%9E%85-%EC%9D%B8%EC%9E%90%EB%A5%BC-%EB%B0%9B%EB%8A%94-%ED%83%80%EC%9E%85-%EB%A7%8C%EB%93%A4%EA%B8%B0-%EC%A0%9C%EB%84%A4%EB%A6%AD-%ED%83%80%EC%9E%85-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0\" aria-label=\" 111 타입 인자를 받는 타입 만들기 제네릭 타입 파라미터 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 11.1 타입 인자를 받는 타입 만들기: 제네릭 타입 파라미터</h2>\n<ul>\n<li>제네릭스를 사용하면 타입 파라미터를 받는 타입을 정의할 수 있다.</li>\n<li>제네릭 타입의 인스턴스가 만들어질 때는 타입 파라미터를 구체적인 타입 인자로 치환한다.</li>\n<li>코틀린 컴파일러는 보통 타입과 마찬가지로 타입 인자도 추론할 수 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">val readers: MutableList&lt;String&gt; = mutableListOf()\nval readers = mutableListOf&lt;String&gt;()</code>\n        </deckgo-highlight-code>\n<ul>\n<li>위 두 선언은 동등하다.</li>\n<li>빈 리스트를 만들어야 한다면 타입 인자를 추론할 근거가 없기에 직접 명시해야 한다.</li>\n<li>코틀린에는 raw 타입이 없다.</li>\n</ul>\n<h3 id=\"-1111-제네릭-타입과-함께-동작하는-함수와-프로퍼티\" style=\"position:relative;\"><a href=\"#-1111-%EC%A0%9C%EB%84%A4%EB%A6%AD-%ED%83%80%EC%9E%85%EA%B3%BC-%ED%95%A8%EA%BB%98-%EB%8F%99%EC%9E%91%ED%95%98%EB%8A%94-%ED%95%A8%EC%88%98%EC%99%80-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0\" aria-label=\" 1111 제네릭 타입과 함께 동작하는 함수와 프로퍼티 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 11.1.1 제네릭 타입과 함께 동작하는 함수와 프로퍼티</h3>\n<ul>\n<li>제네릭 함수를 호출할 때는 반드시 구체적 타입으로 타입인자를 넘겨야 한다.</li>\n<li>함수의 타입 파라미터 T가 수신 객체와 반환 타입에 쓰인다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val letters = (&#39;a&#39;..&#39;z&#39;).toList()\n    println(letters.slice&lt;Char&gt;(0..2))\n    println(letters.slice(10..13))\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>컴파일러는 타입을 추론한다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val authors = listOf(&quot;Sveta&quot;, &quot;Seb&quot;, &quot;Roman&quot;, &quot;Dima&quot;)\n    val readers = mutableListOf&lt;String&gt;(&quot;Seb&quot;, &quot;Hadi&quot;)\n    println(readers.filter { it !in authors })\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>it의 타입은 <code>String</code>이다.</li>\n<li>컴파일러는 <code>filter</code>가 <code>List&#x3C;T></code>타입의 리스트에 대해 호출될 수 있다는 사실과 <code>filter</code>의 수신 객체인 <code>reader</code>의 실제 타입이 <code>List&#x3C;String></code>이라는 사실을 알고 그로부터 추론한다.</li>\n<li>일반 프로퍼티는 타입 파라미터를 가질 수 없지만 확장 프로퍼티는 가질 수 있다.</li>\n</ul>\n<h3 id=\"-1112-제네릭-클래스를-홑화살괄호-구문을-사용해-선언한다\" style=\"position:relative;\"><a href=\"#-1112-%EC%A0%9C%EB%84%A4%EB%A6%AD-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%A5%BC-%ED%99%91%ED%99%94%EC%82%B4%EA%B4%84%ED%98%B8-%EA%B5%AC%EB%AC%B8%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%B4-%EC%84%A0%EC%96%B8%ED%95%9C%EB%8B%A4\" aria-label=\" 1112 제네릭 클래스를 홑화살괄호 구문을 사용해 선언한다 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 11.1.2 제네릭 클래스를 홑화살괄호 구문을 사용해 선언한다.</h3>\n<ul>\n<li>제네릭 클래스를 확장하는 클래스를 정의하려면 기반 타입의 제네릭 파라미터에 대해 타입 인자를 지정해야 한다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class StringList : List&lt;String&gt; {\n    override fun get(index: Int): String = TODO()\n}\n\nclass ArrayList&lt;T&gt; : List&lt;T&gt; {\n    override fun get(index: Int): T = TODO()\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>하위 클래스에서 상위 클래스에 정의된 함수를 오버라이드하거나 사용하려면 타입 인자 T를 구체적 타입 <code>String</code>으로 치환해야 한다.</li>\n<li><code>ArrayList</code> 클래스는 자신만의 타입 파라미터 T를 정의하면서 그 T를 기반 클래스의 타입 인자로 사용한다.</li>\n<li>클래스가 자신을 타입 인자로 참조할 수도 있다.</li>\n</ul>\n<h3 id=\"-1113-제네릭-클래스나-함수가-사용할-수-있는-타입-제한-타입-파라미터-제약\" style=\"position:relative;\"><a href=\"#-1113-%EC%A0%9C%EB%84%A4%EB%A6%AD-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%82%98-%ED%95%A8%EC%88%98%EA%B0%80-%EC%82%AC%EC%9A%A9%ED%95%A0-%EC%88%98-%EC%9E%88%EB%8A%94-%ED%83%80%EC%9E%85-%EC%A0%9C%ED%95%9C-%ED%83%80%EC%9E%85-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0-%EC%A0%9C%EC%95%BD\" aria-label=\" 1113 제네릭 클래스나 함수가 사용할 수 있는 타입 제한 타입 파라미터 제약 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 11.1.3 제네릭 클래스나 함수가 사용할 수 있는 타입 제한: 타입 파라미터 제약</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun &lt;T: Number&gt; oneHalf(value: T): Double {\n    return value.toDouble()\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>타입 파라미터 제약은 클래스나 함수에 사용할 수 있는 타입 인자를 제한하는 기능</li>\n<li>어떤 타입을 제네릭 타입의 타입 파라미터에 대한 <strong>상계</strong>로 지정하면 그 제네릭 타입을 인스턴스화할 때 사용하는 타입 인자는 반드시 그 상계 타입이거나 그 상계 타입의 하위 타입이어야 한다.</li>\n<li>제약을 가하려면 타입 파라미터 이름 뒤에 콜론(:)을 표시하고 그 뒤에 상계 타입을 적으면 된다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun &lt;T: Comparable&lt;T&gt;&gt; max(first: T, second: T): T {\n    return if (first &gt; second) first else second\n}\n\nfun main() {\n    println(max(&quot;kotlin&quot;, &quot;java&quot;))\n    // kotlin\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>max</code>를 비교할 수 없는 값 사이에 호출하면 컴파일 오류 발생</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun &lt;T&gt; ensureTrailingPeriod(seq: T) where T: CharSequence, T: Appendable {\n    if (!seq.endsWith(&#39;.&#39;)) {\n        seq.append(&#39;.&#39;)\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>타입 파라미터에 대해 둘 이상의 제약을 가해야하는 경우</li>\n</ul>\n<h3 id=\"-1114-명시적으로-타입-파라미터를-널이-될-수-없는-타입으로-표시해서-널이-될-수-있는-타입-인자-제외시키기\" style=\"position:relative;\"><a href=\"#-1114-%EB%AA%85%EC%8B%9C%EC%A0%81%EC%9C%BC%EB%A1%9C-%ED%83%80%EC%9E%85-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%EB%A5%BC-%EB%84%90%EC%9D%B4-%EB%90%A0-%EC%88%98-%EC%97%86%EB%8A%94-%ED%83%80%EC%9E%85%EC%9C%BC%EB%A1%9C-%ED%91%9C%EC%8B%9C%ED%95%B4%EC%84%9C-%EB%84%90%EC%9D%B4-%EB%90%A0-%EC%88%98-%EC%9E%88%EB%8A%94-%ED%83%80%EC%9E%85-%EC%9D%B8%EC%9E%90-%EC%A0%9C%EC%99%B8%EC%8B%9C%ED%82%A4%EA%B8%B0\" aria-label=\" 1114 명시적으로 타입 파라미터를 널이 될 수 없는 타입으로 표시해서 널이 될 수 있는 타입 인자 제외시키기 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 11.1.4 명시적으로 타입 파라미터를 널이 될 수 없는 타입으로 표시해서 널이 될 수 있는 타입 인자 제외시키기</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Processor&lt;T&gt; {\n    fun process(value: T) {\n        value?.hashCode()\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>아무런 상계를 정하지 않은 타입 파라미터는 <code>Any?</code>를 상계로 정한 파라미터와 같다.</li>\n<li>T 타입이 널이 될 수 있는 타입이 되지 못하게 막는 아무런 제약이 없기 때</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Processor&lt;T: Any&gt; {\n    fun process(value: T) {\n        value.hashCode()\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>항상 널이 될 수 없는 타입만 타입 인자로 받게 만들려면 타입 파라미터에 제약을 가해야 한다.</li>\n</ul>\n<h2 id=\"-112-실행-시점-제네릭스-동작-소거된-타입-파라미터와-실체화된-타입-파라미터\" style=\"position:relative;\"><a href=\"#-112-%EC%8B%A4%ED%96%89-%EC%8B%9C%EC%A0%90-%EC%A0%9C%EB%84%A4%EB%A6%AD%EC%8A%A4-%EB%8F%99%EC%9E%91-%EC%86%8C%EA%B1%B0%EB%90%9C-%ED%83%80%EC%9E%85-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%EC%99%80-%EC%8B%A4%EC%B2%B4%ED%99%94%EB%90%9C-%ED%83%80%EC%9E%85-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0\" aria-label=\" 112 실행 시점 제네릭스 동작 소거된 타입 파라미터와 실체화된 타입 파라미터 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 11.2 실행 시점 제네릭스 동작: 소거된 타입 파라미터와 실체화된 타입 파라미터</h2>\n<ul>\n<li>JVM의 제네릭스는 보통 <strong>타입소거</strong>를 사용해 구현된다.\n<ul>\n<li>실행 시점에 제네릭 클래스의 인스턴스에 타입 인자 정보가 들어있지 않다.</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"-1121-실행-시점에-제네릭-클래스의-타입-정보를-찾을-때-한계-타입-검사와-캐스팅\" style=\"position:relative;\"><a href=\"#-1121-%EC%8B%A4%ED%96%89-%EC%8B%9C%EC%A0%90%EC%97%90-%EC%A0%9C%EB%84%A4%EB%A6%AD-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%9D%98-%ED%83%80%EC%9E%85-%EC%A0%95%EB%B3%B4%EB%A5%BC-%EC%B0%BE%EC%9D%84-%EB%95%8C-%ED%95%9C%EA%B3%84-%ED%83%80%EC%9E%85-%EA%B2%80%EC%82%AC%EC%99%80-%EC%BA%90%EC%8A%A4%ED%8C%85\" aria-label=\" 1121 실행 시점에 제네릭 클래스의 타입 정보를 찾을 때 한계 타입 검사와 캐스팅 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 11.2.1 실행 시점에 제네릭 클래스의 타입 정보를 찾을 때 한계: 타입 검사와 캐스팅</h3>\n<ul>\n<li>자바와 마찬가지로 코틀린 제네릭 타입 인자 정보는 런타임에 지워진다.</li>\n</ul>\n<h4 id=\"️-타입-소거로-인해-생기는-한계\" style=\"position:relative;\"><a href=\"#%EF%B8%8F-%ED%83%80%EC%9E%85-%EC%86%8C%EA%B1%B0%EB%A1%9C-%EC%9D%B8%ED%95%B4-%EC%83%9D%EA%B8%B0%EB%8A%94-%ED%95%9C%EA%B3%84\" aria-label=\"️ 타입 소거로 인해 생기는 한계 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🛠️ 타입 소거로 인해 생기는 한계</h4>\n<ul>\n<li>타입 인자를 따로 저장하지 않기 때문에 실행 시점에 타입 인자를 검사할 수 없다.</li>\n<li>코틀린에서 파라미터의 타입 인자에 따라 서로 다른 동작을 해야 하는 함수를 작성할 때 문제가 된다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun readNumbersOrWords(): List&lt;Any&gt; {\n    val input = readln()\n    val words: List&lt;String&gt; = input.split(&quot;,&quot;)\n    val numbers: List&lt;Int&gt; = words.mapNotNull { it.toIntOrNull() }\n    return numbers.ifEmpty { words }\n}\n\nfun printList(l: List&lt;Any&gt;) {\n    when(1) {\n        is List&lt;String&gt; -&gt; println(&quot;Strings: $l&quot;) // error\n        is List&lt;Int&gt; -&gt; println(&quot;Integers: $l&quot;) // error\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>실행 시점에 어떤 값이 <code>List</code>인지 여부는 확실히 알아낼 수 있지만 그 리스트가 문자열, 사람 등 실제 어떤 타입의 원소가 들어있는 리스트인지는 알 수 없다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun printSum(c: Collection&lt;*&gt;) {\n    val intList = c as? List&lt;Int&gt; ?: throw IllegalArgumentException(&quot;List is expected&quot;)\n    println(intList.sum())\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>인자를 알 수 없는 제네릭 타입을 표현할 때 스타 프로젝션을 쓰면 된다.</li>\n<li>컴파일러가 경고를 한다는 점을 제외하면 컴파일 된다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun printSum(c: Collection&lt;Int&gt;) {\n    when (c) {\n        is List&lt;Int&gt; -&gt; println(&quot;List sum: ${c.sum()}&quot;)\n        is Set&lt;Int&gt; -&gt; println(&quot;Set sum: ${c.sum()}&quot;)\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>컴파일 시점에 타입 정보가 주어진 경우에는 is 검사 수행이 허용된다.</li>\n</ul>\n<h3 id=\"-1122-실체화된-타입-파라미터를-사용하는-함수는-타입-인자를-실행-시점에-언급할-수-있다\" style=\"position:relative;\"><a href=\"#-1122-%EC%8B%A4%EC%B2%B4%ED%99%94%EB%90%9C-%ED%83%80%EC%9E%85-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%ED%95%A8%EC%88%98%EB%8A%94-%ED%83%80%EC%9E%85-%EC%9D%B8%EC%9E%90%EB%A5%BC-%EC%8B%A4%ED%96%89-%EC%8B%9C%EC%A0%90%EC%97%90-%EC%96%B8%EA%B8%89%ED%95%A0-%EC%88%98-%EC%9E%88%EB%8B%A4\" aria-label=\" 1122 실체화된 타입 파라미터를 사용하는 함수는 타입 인자를 실행 시점에 언급할 수 있다 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 11.2.2 실체화된 타입 파라미터를 사용하는 함수는 타입 인자를 실행 시점에 언급할 수 있다</h3>\n<ul>\n<li>인라인 함수의 타입 파라미터는 실체화된다.\n<ul>\n<li>실행 시점에 인라인 함수의 실제 타입 인자를 알 수 있다</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">inline fun &lt;reified T&gt; isA(value: Any) = value is T\n\nfun main() {\n    println(isA&lt;String&gt;(&quot;abc&quot;))\n    println(isA&lt;String&gt;(123))\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>타입 파라미터를 <code>reified</code>로 지정하면 <code>value</code>의 타입이 T의 인스턴스인지를 실행 시점에 검사할 수 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val items = listOf(&quot;one&quot;, 2, &quot;three&quot;)\n    println(items.filterIsInstance&lt;String&gt;())\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">inline fun &lt;reified R, C : MutableCollection&lt;in R&gt;&gt; Iterable&lt;*&gt;.filterIsInstanceTo(destination: C): C {\n    for (element in this) if (element is R) destination.add(element)\n    return destination\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>filterIsInstance</code> 함수는 인자로 받은 컬렉션에서 지정한 클래스의 인스턴스만을 모아 만든 리스트를 반환</li>\n</ul>\n<h3 id=\"-1123-클래스-참조를-실체화된-타입-파라미터로-대신함으로써-javalangclass-파라미터-피하기\" style=\"position:relative;\"><a href=\"#-1123-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%B0%B8%EC%A1%B0%EB%A5%BC-%EC%8B%A4%EC%B2%B4%ED%99%94%EB%90%9C-%ED%83%80%EC%9E%85-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%EB%A1%9C-%EB%8C%80%EC%8B%A0%ED%95%A8%EC%9C%BC%EB%A1%9C%EC%8D%A8-javalangclass-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0-%ED%94%BC%ED%95%98%EA%B8%B0\" aria-label=\" 1123 클래스 참조를 실체화된 타입 파라미터로 대신함으로써 javalangclass 파라미터 피하기 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 11.2.3 클래스 참조를 실체화된 타입 파라미터로 대신함으로써 java.lang.Class 파라미터 피하기</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">val serviceImpl = ServiceLoader.load(Service::class.java)</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>::class.java</code> 구문은 코틀린 클래스에 대응하는 <code>java.lang.Class</code> 참조를 얻는 방법을 보여준다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">val serviceImpl = loadService&lt;Service&gt;()\n\ninline fun &lt;reified T&gt; loadService() {\n    return ServiceLoader.load(T::class.java)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>클래스를 타입 인자로 지정하면 훨씬 이해하기 쉽다.</li>\n</ul>\n<h3 id=\"-1124-실체화된-타입-파라미터가-있는-접근자-정의\" style=\"position:relative;\"><a href=\"#-1124-%EC%8B%A4%EC%B2%B4%ED%99%94%EB%90%9C-%ED%83%80%EC%9E%85-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%EA%B0%80-%EC%9E%88%EB%8A%94-%EC%A0%91%EA%B7%BC%EC%9E%90-%EC%A0%95%EC%9D%98\" aria-label=\" 1124 실체화된 타입 파라미터가 있는 접근자 정의 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 11.2.4 실체화된 타입 파라미터가 있는 접근자 정의</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">inline val &lt;reified T&gt; T.canonical: String\n    get() = T::class.java.canonicalName</code>\n        </deckgo-highlight-code>\n<ul>\n<li>이 프로퍼티는 제네릭 클래스의 표준적인 이름을 반환한다.</li>\n<li>프로퍼티를 <code>inline</code>으로 표시하고 타입 파라미터를 <code>reified</code>로 하면 타입인자에 쓰인 구체적인 클래스를 참조할 수 있다.</li>\n</ul>\n<h3 id=\"-1125-실체화된-타입-파라미터의-제약\" style=\"position:relative;\"><a href=\"#-1125-%EC%8B%A4%EC%B2%B4%ED%99%94%EB%90%9C-%ED%83%80%EC%9E%85-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%EC%9D%98-%EC%A0%9C%EC%95%BD\" aria-label=\" 1125 실체화된 타입 파라미터의 제약 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 11.2.5 실체화된 타입 파라미터의 제약</h3>\n<p>실체화된 타입 파라미터 사용할 수 있는 경우</p>\n<ul>\n<li>타입 검사와 캐스팅(is, !is, as, as?)</li>\n<li>10장에서 설명할 코틀린 리플렉션 API(::class)</li>\n<li>코틀린 타입에 대응하는 <code>Java.lang.Class</code>를 얻기(::class, java)</li>\n<li>다른 함수를 호출할 때 타입 인자로 사용</li>\n</ul>\n<p>실체화된 타입 파라미터 사용할 수 없는 경우</p>\n<ul>\n<li>타입 파라미터 클래스의 인스턴스 생성하기</li>\n<li>타입 파라미터 클래스의 동반 객체 메서드 호출하기</li>\n<li>실체화된 타입 파라미터를 요구하는 함수를 호출하면서 실체화하지 않은 타입 파라미터로 받은 타입을 타입 인자로 넘기기</li>\n<li>클래스, 프로퍼티, 인라인 함수가 아닌 함수의 타입 파라미터를 <code>reified</code>로 지정하기</li>\n</ul>\n<h2 id=\"-113-변성은-제네릭과-타입-인자-사이의-하위-타입-관계를-기술\" style=\"position:relative;\"><a href=\"#-113-%EB%B3%80%EC%84%B1%EC%9D%80-%EC%A0%9C%EB%84%A4%EB%A6%AD%EA%B3%BC-%ED%83%80%EC%9E%85-%EC%9D%B8%EC%9E%90-%EC%82%AC%EC%9D%B4%EC%9D%98-%ED%95%98%EC%9C%84-%ED%83%80%EC%9E%85-%EA%B4%80%EA%B3%84%EB%A5%BC-%EA%B8%B0%EC%88%A0\" aria-label=\" 113 변성은 제네릭과 타입 인자 사이의 하위 타입 관계를 기술 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 11.3 변성은 제네릭과 타입 인자 사이의 하위 타입 관계를 기술</h2>\n<ul>\n<li>변성 개념은 기저 타입이 같고 타입 인자가 다른 여러 타입이 서로 어떤 관계가 있는지 설명하는 개념</li>\n</ul>\n<h3 id=\"-1131-변성은-인자를-함수에-넘겨도-안전한지-판단하게-해준다\" style=\"position:relative;\"><a href=\"#-1131-%EB%B3%80%EC%84%B1%EC%9D%80-%EC%9D%B8%EC%9E%90%EB%A5%BC-%ED%95%A8%EC%88%98%EC%97%90-%EB%84%98%EA%B2%A8%EB%8F%84-%EC%95%88%EC%A0%84%ED%95%9C%EC%A7%80-%ED%8C%90%EB%8B%A8%ED%95%98%EA%B2%8C-%ED%95%B4%EC%A4%80%EB%8B%A4\" aria-label=\" 1131 변성은 인자를 함수에 넘겨도 안전한지 판단하게 해준다 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 11.3.1 변성은 인자를 함수에 넘겨도 안전한지 판단하게 해준다</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun printContents(list: List&lt;Any&gt;) {\n    println(list.joinToString())\n}\n\nfun main() {\n    printContents(listOf(&quot;abc&quot;, &quot;bac&quot;))\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>위 코드는 잘 동작한다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun addAnswer(list: MutableList&lt;Any&gt;) {\n    list.add(42)\n}\n\nfun main() {\n    val strings = mutableListOf(&quot;abc&quot;, &quot;bac&quot;)\n    addAnswer(strings) // error\n    println(strings.maxBy { it.length })\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>List&#x3C;Any></code>타입의 파라미터를 받는 함수에 <code>List&#x3C;String></code>을 넘길 수 없다.</li>\n<li>다만, 원소 추가나 변경이 없는 경우에는 안전하다.</li>\n</ul>\n<h3 id=\"-1132-클래스-타입-하위-타입\" style=\"position:relative;\"><a href=\"#-1132-%ED%81%B4%EB%9E%98%EC%8A%A4-%ED%83%80%EC%9E%85-%ED%95%98%EC%9C%84-%ED%83%80%EC%9E%85\" aria-label=\" 1132 클래스 타입 하위 타입 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 11.3.2 클래스, 타입, 하위 타입</h3>\n<ul>\n<li>제네릭 클래스가 아닌 클래스에서는 클래스 이름을 바로 타입으로 쓸 수 있다.</li>\n<li>모든 클래스가 적어도 둘 이상의 타입을 구성할 수 있다.</li>\n<li>제네릭 클래스에서는 올바른 타입을 얻으려면 제네릭 타입의 타입 파라미터를 구체적인 타입 인자로 바꿔줘야 한다.</li>\n<li>어떤 타입 A의 값이 필요한 모든 장소에 어떤 타입 B의 값을 넣어도 아무 문제가 없다면 타입 B는 타입 A의 하위 타입이다.</li>\n<li>A 타입이 B 타입의 하위 타입이라면 B는 A의 상위 타입이다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun test(i: Int) {\n    val n: Number = i\n    \n    fun f(s: String) {\n        //..\n    }\n    f(i) // error\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>어떤 값의 타입이 변수 타입의 하위 타입인 경우에만 값을 변수에 대입하도록 허용한다.</li>\n<li>하위 타입은 하위 클래스와 근본적으로 같다.</li>\n<li>널이 될 수 없는 타입은 널이 될 수 있는 타입의 하위 타입이다.</li>\n<li>어떤 제네릭 타입(<code>MutableList</code>)이 있는데 서로 다른 두 타입 A와 B에 대해 <code>MutableList&#x3C;A></code>가 항상 <code>MutableList&#x3C;B></code>의 하위 타입도 아니고 상위 타입도 아닌 경우에 이 제네릭 타입이 타입 파라미터에 대해 무공변이라고 말한다.\n<ul>\n<li>자바에서는 모든 클래스가 무공변이다.</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"-1133-공변성은-하위-타입-관계를-유지한다\" style=\"position:relative;\"><a href=\"#-1133-%EA%B3%B5%EB%B3%80%EC%84%B1%EC%9D%80-%ED%95%98%EC%9C%84-%ED%83%80%EC%9E%85-%EA%B4%80%EA%B3%84%EB%A5%BC-%EC%9C%A0%EC%A7%80%ED%95%9C%EB%8B%A4\" aria-label=\" 1133 공변성은 하위 타입 관계를 유지한다 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 11.3.3 공변성은 하위 타입 관계를 유지한다</h3>\n<ul>\n<li>공변적인 클래스는 제네릭 클래스(<code>Producer&#x3C;T></code>)에 대해 A가 B의 하위 타입일 때 <code>Producer&#x3C;A></code>가 <code>Producer&#x3C;B></code>의 하위 타입인 경우를 말한다.\n<ul>\n<li>이를 \"하위 타입 관계를 유지한다.\" 라고 말한다.</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">interface Producer&lt;out T&gt; {\n    fun produce(): T\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>코틀린에서 제네릭 클래스가 타입 파라미터에 대해 공변적임을 표시하려면 타입 파라미터 이름 앞에 <code>out</code>을 넣어야 한다.</li>\n<li>클래스의 타입 파라미터를 공변적으로 만들면 함수 정의에 사용한 파라미터 타입과 타입 인자의 타입이 정확히 일치하지 않더라도 그 클래스의 인스턴스를 함수 인자나 반환값으로 사용할 수 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">open class Animal {\n    fun feed() {\n        //\n    }\n}\n\nclass Herd&lt;T: Animal&gt; {\n    val size: Int get() = 5\n    operator fun get(i: Int): T {\n        //\n    }\n}\n\nfun feedAll(animals: Herd&lt;Animal&gt;) {\n    for (i in 0..&lt;animals.size) {\n        animals[i].feed()\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>무공변 컬렉션 역할을 하는 클래스 정의이다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Cat: Animal() {\n    fun cleanLitter() {\n        //\n    }\n}\n\nfun takeCareOfCats(cats: Herd&lt;Cat&gt;) {\n    for (i in 0..&lt;cats.size) {\n        cats[i].cleanLitter()\n    }\n    feedAll(cats) // error\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>타입 불일치 오류가 난다.</li>\n<li>고양이 무리는 동물 무리의 하위 클래스가 아니기 때문이다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Herd&lt;out T: Animal&gt; {\n    val size: Int get() = 5\n    operator fun get(i: Int): T {\n        //\n    }\n}\n\nfun takeCareOfCats(cats: Herd&lt;Cat&gt;) {\n  for (i in 0..&lt;cats.size) {\n    cats[i].cleanLitter()\n  }\n  feedAll(cats)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>캐스팅을 하지 않고도 에러가 발생하지 않는다.</li>\n<li>타입 파라미터를 공변적으로 지정하면 클래스 내부에서 그 파라미터를 사용하는 방법을 제한한다.</li>\n<li>타입 안전성을 보장하기 위해 공변적 파라미터는 항상 out 위치에만 있어야 한다.\n<ul>\n<li>클래스가 T 타입의 값을 생산할 수는 있지만 소비할 수 없다는 뜻</li>\n</ul>\n</li>\n<li>클래스 멤버를 선언할 때 타입 파라미터를 사용할 수 있는 지점은 모두 인과 아웃 위치로 나뉜다.\n<ul>\n<li>함수의 반환 타입: 아웃 위치</li>\n<li>함수의 파라미터 타입: 인 위치</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">interface MutableList&lt;T&gt; : List&lt;T&gt;, MutableCollection&lt;T&gt; {\n    override fun add(element: T): Boolean\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>MutableList</code>는 T에 대해 공변적일 수 없다. T가 인 위치에 쓰이기 때문이다.</li>\n<li>생성자 파라미터는 인이나 아웃 위치 어느 쪽도 아니라는 사실에 유의하자.</li>\n<li>변성은 코드에서 위험할 여지가 있는 메서드를 호출할 수 없게 만듦으로써 제네릭 타입의 인스턴스 역할을 하는 클래스 인스턴스를 잘못 사용하는 일이 없게 방지하는 역할을 한다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Herd&lt;T: Animal&gt;(var leadAnimal: T, vararg animals: T) {}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>leadAnimal</code> 프로퍼티가 인 위치에 있기 때문에 T를 <code>out</code>으로 표시할 수 없다.</li>\n<li>이러한 위치 규칙은 외부에서 볼 수 있는 API에만 적용할 수 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Herd&lt;out T: Animal&gt;(private var leadAnimal: T, vararg animals: T) {}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>private 메서드의 파라미터는 인도 아니고 아웃도 아닌 위치다.</li>\n<li><code>Herd</code>를 T에 대해 공변적으로 선언해도 안전하다.</li>\n</ul>\n<h3 id=\"-1134-반공변성은-하위-타입-관계를-뒤집는다\" style=\"position:relative;\"><a href=\"#-1134-%EB%B0%98%EA%B3%B5%EB%B3%80%EC%84%B1%EC%9D%80-%ED%95%98%EC%9C%84-%ED%83%80%EC%9E%85-%EA%B4%80%EA%B3%84%EB%A5%BC-%EB%92%A4%EC%A7%91%EB%8A%94%EB%8B%A4\" aria-label=\" 1134 반공변성은 하위 타입 관계를 뒤집는다 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 11.3.4 반공변성은 하위 타입 관계를 뒤집는다</h3>\n<ul>\n<li>반공변 클래스의 하위 타입 관계는 그 클래스의 타입 파라미터의 상하위 타입 관계와 반대다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">sealed class Fruit {\n    abstract val weight: Int\n}\n\ndata class Apple(override val weight: Int, val color: String) : Fruit()\n\ndata class Orange(override val weight: Int, val juicy: Boolean) : Fruit()\n\nfun main() {\n  val weightComparator = Comparator&lt;Fruit&gt; {\n      a, b -&gt; a.weight - b.weight\n  }\n  val fruits: List&lt;Fruit&gt; = listOf(Apple(100, &quot;green&quot;), Orange(180, true))\n  val apples: List&lt;Apple&gt; = listOf(Apple(50, &quot;red&quot;), Apple(120, &quot;green&quot;) ,Apple(155, &quot;yellow&quot;))\n  println(fruits.sortedWith(weightComparator))\n  println(apples.sortedWith(weightComparator))\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>sortedWith</code> 함수는 <code>Comparator&#x3C;String></code>을 요구하므로 일반적인 타입을 비교할 수 있는 <code>Comparator</code>를 넘겨도 안전하다.</li>\n<li>어떤 타입의 객체를 <code>Comparator</code>로 비교해야 한다면 그 타입이나 그 타입의 조상 타입을 비교할 수 있는 <code>Comparator</code>를 사용할 수 있다.</li>\n<li>반공변성: 어떤 클래스(<code>Consumer&#x3C;T></code>)에 대해 타입 B가 타입 A의 하위 타입일 때 <code>Consumer&#x3C;A></code>가 <code>Consumer&#x3C;B></code>의 하위 타입인 관계가 성립하면 제네릭 클래스는 타입 인자 T에 대해 반공변이다.</li>\n<li>in 이라는 키워드는 그 키워드가 붙은 타입이 이 클래스의 메서드 안으로 전달돼 메서드에 의해 소비된다는 뜻</li>\n</ul>\n<h3 id=\"-1135-사용-지점-변성을-사용해-타입이-언급되는-지점에서-변성-지정\" style=\"position:relative;\"><a href=\"#-1135-%EC%82%AC%EC%9A%A9-%EC%A7%80%EC%A0%90-%EB%B3%80%EC%84%B1%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%B4-%ED%83%80%EC%9E%85%EC%9D%B4-%EC%96%B8%EA%B8%89%EB%90%98%EB%8A%94-%EC%A7%80%EC%A0%90%EC%97%90%EC%84%9C-%EB%B3%80%EC%84%B1-%EC%A7%80%EC%A0%95\" aria-label=\" 1135 사용 지점 변성을 사용해 타입이 언급되는 지점에서 변성 지정 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 11.3.5 사용 지점 변성을 사용해 타입이 언급되는 지점에서 변성 지정</h3>\n<ul>\n<li>클래스를 선언하면서 변성을 지정하면 그 클래스를 사용하는 모든 장소에 변성 지정자가 영향을 끼치므로 편리하다.\n<ul>\n<li>선언 지점 변성이라고 함.</li>\n</ul>\n</li>\n<li>자바에서는 타입 파라미터가 있는 타입을 사용할 때마다 그 타입 파라미터를 하위 타입이나 상위 타입 중 어떤 타입으로 대치할 수 있는지 명시해야 한다.\n<ul>\n<li>사용 지점 변성이라고 함.</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun &lt;T&gt; copyData(source: MutableList&lt;T&gt;, destination: MutableList&lt;T&gt;) {\n    for (item in source) destination.add(item)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>무공변 파라미터 타입을 사용하는 데이터 복사 함수</li>\n<li>두 컬렉션의 원소 타입이 정확하게 일치할 필요가 없다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun &lt;T: R, R&gt; copyData(source: MutableList&lt;T&gt;, destination: MutableList&lt;R&gt;) {\n    for (item in source) destination.add(item)\n}\n\nfun main() {\n    val ints = mutableListOf(1, 2, 3)\n    val anyItems = mutableListOf&lt;Any&gt;()\n    copyData(ints, anyItems)\n    println(anyItems)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>int</code>가 <code>Any</code>의 하위 타입이기 때문에 정상 동작</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun &lt;T&gt; copyData(source: MutableList&lt;out T&gt;, destination: MutableList&lt;T&gt;) {\n  for (item in source) destination.add(item)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>out 키워드를 타입을 사용하는 위치 앞에 붙이면 T 타입을 in 위치에 사용하는 메서드를 호출하지 않는다는 뜻</li>\n<li>타입 선언에서 타입 파라미터를 사용하는 위치라면 어디에나 변성 변경자를 붙일 수 있다.\n<ul>\n<li>이때 타입 프로젝션이 일어난다.</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val list: MutableList&lt;out Number&gt; = mutableListOf()\n    list.add(42) // error\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>프로젝션 타입 대신 일반 타입을 사용하면 된다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun &lt;T&gt; copyData(source: MutableList&lt;T&gt;, destination: MutableList&lt;in T&gt;) {\n    for (item in source) destination.add(item)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>원본 리스트 원소 타입의 상위 타입을 대상 리스트 원소 타입으로 허용</li>\n</ul>\n<h3 id=\"-1136-스타-프로젝션-제네릭-타입-인자에-대한-정보가-없음을-표현하고자--사용\" style=\"position:relative;\"><a href=\"#-1136-%EC%8A%A4%ED%83%80-%ED%94%84%EB%A1%9C%EC%A0%9D%EC%85%98-%EC%A0%9C%EB%84%A4%EB%A6%AD-%ED%83%80%EC%9E%85-%EC%9D%B8%EC%9E%90%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A0%95%EB%B3%B4%EA%B0%80-%EC%97%86%EC%9D%8C%EC%9D%84-%ED%91%9C%ED%98%84%ED%95%98%EA%B3%A0%EC%9E%90--%EC%82%AC%EC%9A%A9\" aria-label=\" 1136 스타 프로젝션 제네릭 타입 인자에 대한 정보가 없음을 표현하고자  사용 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 11.3.6 스타 프로젝션: 제네릭 타입 인자에 대한 정보가 없음을 표현하고자 * 사용</h3>\n<ul>\n<li><code>MutableList&#x3C;*></code>는 <code>MutableList&#x3C;Any?></code>와 같지 않다.\n<ul>\n<li><code>MutableList&#x3C;*></code>는 어떤 정해진 구체적인 타입의 원소만을 담는 리스트지만 그 원소의 타입을 정확히 모른다는 사실을 표현</li>\n<li><code>MutableList&#x3C;Any?></code>는 모든 타입의 원소를 담을 수 있음을 알 수 있는 리스트다.</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n  val list: MutableList&lt;Any?&gt; = mutableListOf(&#39;a&#39;, 1, &quot;qwe&quot;)\n  val chars = mutableListOf(&#39;a&#39;, &#39;b&#39;, &#39;c&#39;)\n  val unknownElements: MutableList&lt;*&gt; = if (Random.nextBoolean()) list else chars\n  println(unknownElements.first())\n  unknownElements.add(42) // error\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>이 맥락에서 <code>MutableList&#x3C;*></code>는 <code>MutableList&#x3C;out Any?></code>처럼 프로젝션된다.</li>\n<li>원소 타입을 모르더라도 안전하게 원소를 꺼내올 수는 있지만 타입을 모르는 리스트에 원소를 마음대로 넣을 수는 없다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun printFirst(list: List&lt;*&gt;) {\n    if (list.isNotEmpty()) {\n        println(list.first())\n    }\n}\n\nfun main() {\n    printFirst(listOf(&quot;Sveta&quot;, &quot;Seb&quot;, &quot;Dima&quot;, &quot;Roman&quot;))\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>구체적인 타입을 신경쓰지 않고 읽기만 할 때 스타 프로젝션을 쓴다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun &lt;T&gt; printFirst(list: List&lt;T&gt;) {\n    if (list.isNotEmpty()) {\n        println(list.first())\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>이 경우에도 모든 리스트를 인자로 받을 수 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">interface FieldValidator&lt;in T&gt; {\n    fun validate(input: T): Boolean\n}\n\nobject DefaultStringValidator : FieldValidator&lt;String&gt; {\n    override fun validate(input: String) = input.isNotEmpty()\n}\n\nobject DefaultIntValidator : FieldValidator&lt;Int&gt; {\n    override fun validate(input: Int) = input &gt;= 0\n}\n\nfun main() {\n  val validator = mutableMapOf&lt;KClass&lt;*&gt;, FieldValidator&lt;*&gt;&gt;()\n  validator[String::class] = DefaultStringValidator\n  validator[Int::class] = DefaultIntValidator\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>String 타입의 필드를 <code>FieldValidator&#x3C;*></code> 타입의 검증기로 검증할 수 없기 때문에 문제가 생긴다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">    val stringValidator = validator[String::class] as FieldValidator&lt;String&gt;</code>\n        </deckgo-highlight-code>\n<ul>\n<li>명시적 타입 캐스팅을 사용하면 사용할 수 있지만 warning이 발생한다.</li>\n<li>또한 값 검증 메서드 안에서 실패한다.\n<ul>\n<li>실행 시점에 모든 제네릭 타입 정보가 지워지기 때</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val validator = mutableMapOf&lt;KClass&lt;*&gt;, FieldValidator&lt;*&gt;&gt;()\n    val stringValidator = validator[Int::class] as FieldValidator&lt;String&gt;\n    stringValidator.validate(&quot;&quot;) // 실행 시점 에러\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>검증기를 잘못 가져왔지만 컴파일이 성공한다.</li>\n<li>결국 캐스팅으로 해결하는 것은 타입 안전성을 보장할 수도 없고 실수를 하기도 쉽다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">object Validators {\n  private val validators = mutableMapOf&lt;KClass&lt;*&gt;, FieldValidator&lt;*&gt;&gt;()\n\n  fun &lt;T : Any&gt; registerValidator(kClass: KClass&lt;T&gt;, fieldValidator: FieldValidator&lt;T&gt;) {\n    validators[kClass] = fieldValidator\n  }\n\n  @Suppress(&quot;UNCHECKED_CAST&quot;)\n  operator fun &lt;T : Any&gt; get(kClass: KClass&lt;T&gt;): FieldValidator&lt;T&gt; =\n    validators[kClass] as? FieldValidator&lt;T&gt; ?: throw IllegalArgumentException(\n      &quot;No validator for ${kClass.simpleName}&quot;\n    )\n}\n\nfun main() {\n  Validators.registerValidator(String::class, DefaultStringValidator)\n  Validators.registerValidator(Int::class, DefaultIntValidator)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>타입 안전성을 보장하는 API이다.</li>\n<li>이 패턴을 모든 커스텀 제네릭 클래스를 저장할 때 사용할 수 있게 확장할 수도 있다.</li>\n</ul>\n<h3 id=\"-1137-타입-설명\" style=\"position:relative;\"><a href=\"#-1137-%ED%83%80%EC%9E%85-%EC%84%A4%EB%AA%85\" aria-label=\" 1137 타입 설명 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 11.3.7 타입 설명</h3>\n<ul>\n<li>타입 별명은 기존 타입에 대해 다른 이름을 부여한다.</li>\n<li><code>typealias</code> 키워드 뒤에 별명을 적어 타입 별명 선언을 시작할 수 있다.</li>\n<li>긴 제네릭 타입을 짧게 부를 때 유용하다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">typealias NameCombiner = (String, String, String, String) -&gt; String\n\nval authorsCombiner: NameCombiner = { a, b, c, d -&gt; &quot;$a et al.&quot; }\nval bandCombiner: NameCombiner = { a, b, c, d -&gt; &quot;$a, $b &amp; The Gang&quot; }\n\nfun combineAuthors(combiner: NameCombiner) {\n    println(combiner(&quot;Sveta&quot;, &quot;Seb&quot;, &quot;Dima&quot;, &quot;Roman&quot;))\n}\n\nfun main() {\n    combineAuthors(bandCombiner)\n    combineAuthors(authorsCombiner)\n    combineAuthors { a, b, c, d -&gt; &quot;$d, $c &amp; Co.&quot; }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>타입 별명을 도입하면 코드를 읽을 때 좀 더 쉽게 이해가 되도록 함수형 타입에 새로운 맥락을 부여할 수 있다.</li>\n</ul>","excerpt":"📖 11.1 타입 인자를 받는 타입 만들기: 제네릭 타입 파라미터 제네릭스를 사용하면 타입 파라미터를 받는 타입을 정의할 수 있다. 제네릭 타입의 인스턴스가 만들어질 때는 타입 파라미터를 구체적인 타입 인자로 치환한다. 코틀린 컴파일러는 보통 타입과 마찬가지로 타입 인자도 추론할 수 있다. 위 두 선언은 동등하다. 빈 리스트를 만들어야 한다면 타입 인자를 추론할 근거가 없기에 직접 명시해야 한다. 코틀린에는 raw 타입이 없다. 🔖 11.1.…","fields":{"slug":"/backend/kotlin-in-action/11장-제네릭스/"},"frontmatter":{"title":"Kotlin in Action - 11장 제네릭스","thumbnail":{"childImageSharp":{"fluid":{"src":"/static/f7f7ddfa31d1614405dc5af1487b9ec4/9c94d/kotlin-in-action.png"}}},"draft":false,"category":"Back-End","tags":["Kotlin"],"date":"May 18, 2025"}},"node":{"id":"19b26918-c9bd-5dc5-9a91-76021099d3ff","html":"<h2 id=\"-101-다른-함수를-인자로-받거나-반환하는-함수-정의-고차-함수\" style=\"position:relative;\"><a href=\"#-101-%EB%8B%A4%EB%A5%B8-%ED%95%A8%EC%88%98%EB%A5%BC-%EC%9D%B8%EC%9E%90%EB%A1%9C-%EB%B0%9B%EA%B1%B0%EB%82%98-%EB%B0%98%ED%99%98%ED%95%98%EB%8A%94-%ED%95%A8%EC%88%98-%EC%A0%95%EC%9D%98-%EA%B3%A0%EC%B0%A8-%ED%95%A8%EC%88%98\" aria-label=\" 101 다른 함수를 인자로 받거나 반환하는 함수 정의 고차 함수 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 10.1 다른 함수를 인자로 받거나 반환하는 함수 정의: 고차 함수</h2>\n<ul>\n<li>고차 할수는 다른 할수를 인자로 받거나 함수를 반환하는 합수</li>\n<li>코물린에서는 다나 할수 참조를 사용해 함수를 값으로 표현할 수 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">list.filter { it &gt; 0}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>표준 라이브러리 함수인 filter는 술어 함수를 인자로 받으므로 고차 함수</li>\n</ul>\n<h3 id=\"-1011-함수-타입은-람다의-파라미터-타입과-반환-타입을-지정한다\" style=\"position:relative;\"><a href=\"#-1011-%ED%95%A8%EC%88%98-%ED%83%80%EC%9E%85%EC%9D%80-%EB%9E%8C%EB%8B%A4%EC%9D%98-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0-%ED%83%80%EC%9E%85%EA%B3%BC-%EB%B0%98%ED%99%98-%ED%83%80%EC%9E%85%EC%9D%84-%EC%A7%80%EC%A0%95%ED%95%9C%EB%8B%A4\" aria-label=\" 1011 함수 타입은 람다의 파라미터 타입과 반환 타입을 지정한다 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 10.1.1 함수 타입은 람다의 파라미터 타입과 반환 타입을 지정한다</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">val sum = { x: Int, y: Int -&gt; x + y }\nval action = { println(42) }</code>\n        </deckgo-highlight-code>\n<ul>\n<li>컴파일러는 sum과 action이 함수 타입임을 추론</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">val sum: (Int, Int) -&gt; Int = { x, y -&gt; x + y } // Int 파라미터를 2개 받아서 Int 값을 반환하는 함수\nval action: () -&gt; Unit = { println(42) } // 아무 인자도 받지 않고 아무 값도 반환하지 않는 함수</code>\n        </deckgo-highlight-code>\n<ul>\n<li>함수 타입을 정의하려면 함수 파라미터의 타입을 팔호 안에 넣고 그 뒤에 화살표(->)를 추가한 다음, 함수의 반환 타입을 지정</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">var canReturnNu11: (Int, Int) -&gt; Int? = { x, y -&gt; null }</code>\n        </deckgo-highlight-code>\n<ul>\n<li>다른 함수와 마찬가지로 함수 타입에서도 반환 타입을 널이 될 수 있는 타입으로 지정할 수 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">var funOrNull: ((Int, Int) -&gt; Int)? = null</code>\n        </deckgo-highlight-code>\n<ul>\n<li>함수 전체가 널이 될 수 있는 타입임을 선언하기 위해 함수 타입을 괄호로 감싸고 그 뒤에 물음표를 붙여야만 한다.</li>\n</ul>\n<h3 id=\"-1012-인자로-전달-받은-함수-호출\" style=\"position:relative;\"><a href=\"#-1012-%EC%9D%B8%EC%9E%90%EB%A1%9C-%EC%A0%84%EB%8B%AC-%EB%B0%9B%EC%9D%80-%ED%95%A8%EC%88%98-%ED%98%B8%EC%B6%9C\" aria-label=\" 1012 인자로 전달 받은 함수 호출 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 10.1.2 인자로 전달 받은 함수 호출</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun twoAndThree(operation: (Int, Int) -&gt; Int) {\n    val result = operation(2, 3)\n    println(&quot;The result is $result&quot;)\n}\n\nfun main() {\n    twoAndThree { a, b -&gt; a + b }\n    // The result is 5\n    twoAndThree { a, b -&gt; a * b }\n    // The result is 6\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>인자로 받은 함수를 호출하는 구문은 일반함수를 호출하는 구문과 같다.</li>\n<li>함수 타입에서 파라미터 이름을 지정할 수 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun String.filter(predicate: (Char) -&gt; Boolean): String {\n    return buildString {\n        for (char in this@filter) {\n            if (predicate(char)) append(char)\n        }\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>filter 함수는 술어를 파라미터로 받는다.</li>\n<li>확장 함수와 buildString 함수 모두 수신 객체를 정의하기 때문에 this 앞에 레이블읇 붙여 buildString 람다의 수신 객체가 아니라 filter의 바깥쪽 수신 객체에 접근해야 한다.</li>\n</ul>\n<h3 id=\"-1013-자바에서-코틀린-함수-타입-사용\" style=\"position:relative;\"><a href=\"#-1013-%EC%9E%90%EB%B0%94%EC%97%90%EC%84%9C-%EC%BD%94%ED%8B%80%EB%A6%B0-%ED%95%A8%EC%88%98-%ED%83%80%EC%9E%85-%EC%82%AC%EC%9A%A9\" aria-label=\" 1013 자바에서 코틀린 함수 타입 사용 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 10.1.3 자바에서 코틀린 함수 타입 사용</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun processTheAnswer (f: (Int) -&gt; Int) {\n    printin(f(42))\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">processTheAnswer(number -&gt; number + 1);</code>\n        </deckgo-highlight-code>\n<ul>\n<li>자동 SAM 변환을 통해 코틀린 람다를 함수형 인터페이스를 요구하는 자바 메서드에게 넘길 수 있다. 즉, 자바에서 정의된 고차 함수를 아무 문제 없이 사용할 수 있다는 의미다.</li>\n<li>자바에서 람다를 인자로 받는 코틀린 확장함수를 사용할 때는 첫 번째 인자로 수신 객체를 명시적으로 전달해야 한다.</li>\n</ul>\n<h3 id=\"-1014-함수-타입의-파라미터에-대해-기본값을-지정할-수-있고-널이-될-수도-있다\" style=\"position:relative;\"><a href=\"#-1014-%ED%95%A8%EC%88%98-%ED%83%80%EC%9E%85%EC%9D%98-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%EC%97%90-%EB%8C%80%ED%95%B4-%EA%B8%B0%EB%B3%B8%EA%B0%92%EC%9D%84-%EC%A7%80%EC%A0%95%ED%95%A0-%EC%88%98-%EC%9E%88%EA%B3%A0-%EB%84%90%EC%9D%B4-%EB%90%A0-%EC%88%98%EB%8F%84-%EC%9E%88%EB%8B%A4\" aria-label=\" 1014 함수 타입의 파라미터에 대해 기본값을 지정할 수 있고 널이 될 수도 있다 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 10.1.4 함수 타입의 파라미터에 대해 기본값을 지정할 수 있고, 널이 될 수도 있다.</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun &lt;T&gt; Collection&lt;T&gt;.joinToString(separator: String = &quot;, &quot;, prefix: String = &quot;&quot;, postfix: String = &quot;&quot;): String {\n    val result = StringBuilder(prefix)\n    \n    for ((index, element) in this.withIndex()) {\n        if (index &gt; 0) result.append(separator)\n        result.append(element)\n    }\n    result.append(postfix)\n    return result.toString()\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>이 구현은 유연하지만 핵심 요소인 컬렉션의 각 원소를 문자열로 변환하는 방법을 제어할 수 없다는 단점이 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun &lt;T&gt; Collection&lt;T&gt;.joinToString(separator: String = &quot;, &quot;, prefix: String = &quot;&quot;, postfix: String = &quot;&quot;, transform: (T) -&gt; String = { it.toString() }): String {\n    val result = StringBuilder(prefix)\n\n    for ((index, element) in this.withIndex()) {\n        if (index &gt; 0) result.append(separator)\n        result.append(transform(element))\n    }\n    result.append(postfix)\n    return result.toString()\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>함수 타입에 대한 기본값을 선언할 때 특별한 구문이 필요하지는 않다.\n<ul>\n<li>= 뒤에 람다를 넣으면 된다.</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun &lt;T&gt; Collection&lt;T&gt;.joinToString(separator: String = &quot;, &quot;, prefix: String = &quot;&quot;, postfix: String = &quot;&quot;, transform: ((T) -&gt; String)? = null): String {\n    val result = StringBuilder(prefix)\n\n    for ((index, element) in this.withIndex()) {\n        if (index &gt; 0) result.append(separator)\n        val str = transform?.invoke(element) ?: element.toString()\n        result.append(str)\n    }\n    result.append(postfix)\n    return result.toString()\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>transform은 넘이 될 수 있는 함수 타입이지만 그 반환 타입은 널이 될 수 없는 타입이다.</li>\n<li>transform은 자신이 null이 아니면 String 타입의 널이 아닌 값을 반환한다는 사실을 보장한다.</li>\n</ul>\n<h3 id=\"-1015-함수를-함수에서-반환\" style=\"position:relative;\"><a href=\"#-1015-%ED%95%A8%EC%88%98%EB%A5%BC-%ED%95%A8%EC%88%98%EC%97%90%EC%84%9C-%EB%B0%98%ED%99%98\" aria-label=\" 1015 함수를 함수에서 반환 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 10.1.5 함수를 함수에서 반환</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun getShippingCostCalculator(delivery: Delivery): (Order) -&gt; Double {\n    if (delivery == Delivery.EXPEDITED) {\n        return { order -&gt; 6 + 2.1 * order.itemCount }\n    }\n    return { order -&gt; 1.2 * order.itemCount }\n}\n\nfun main() {\n    val calculator = getShippingCostCalculator(Delivery.EXPEDITED)\n    println(&quot;Shipping costs ${calculator(Order(3))}&quot;)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>다른 함수를 반환하는 함수를 정의하려면 함수의 반환 타입으로 함수 타입을 지정하면 된다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class ContactListFilters {\n    var prefix: String = &quot;&quot;\n    var onlyWithPhoneNumber: Boolean = false\n\n    fun getPredicate(): (Person) -&gt; Boolean {\n        val startWithPrefix = { p: Person -&gt; p.firstName.startsWith(prefix) || p.lastName.startsWith(prefix)}\n        if (!onlyWithPhoneNumber) {\n            return startWithPrefix\n        }\n        return { startWithPrefix(it) &amp;&amp; it.phoneNumber != null }\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>getPredicate method는 filter 함수에 인자로 넘길 수 있는 함수를 반환한다.</li>\n<li>고차 함수는 코드 구조를 개선하고 중복을 없앨 때 쓸 수 있는 아주 강력한 도구다.</li>\n</ul>\n<h3 id=\"-1016-람다를-활용해-중복을-줄여-코드-재사용성-높이기\" style=\"position:relative;\"><a href=\"#-1016-%EB%9E%8C%EB%8B%A4%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%B4-%EC%A4%91%EB%B3%B5%EC%9D%84-%EC%A4%84%EC%97%AC-%EC%BD%94%EB%93%9C-%EC%9E%AC%EC%82%AC%EC%9A%A9%EC%84%B1-%EB%86%92%EC%9D%B4%EA%B8%B0\" aria-label=\" 1016 람다를 활용해 중복을 줄여 코드 재사용성 높이기 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 10.1.6 람다를 활용해 중복을 줄여 코드 재사용성 높이기</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">data class SiteVisit(\n    val path: String,\n    val duration: Double,\n    val os: OS\n)\n\nenum class OS { WINDOWS, LINUX, MAC, IOS, ANDROID }\n\nval log = listOf(\n    SiteVisit(&quot;/&quot;, 34.0, OS.WINDOWS),\n    SiteVisit(&quot;/&quot;, 22.0, OS.MAC),\n    SiteVisit(&quot;/login&quot;, 12.0, OS.WINDOWS),\n    SiteVisit(&quot;/signup&quot;, 8.0, OS.IOS),\n    SiteVisit(&quot;/&quot;, 16.3, OS.ANDROID),\n)\n\nval averageWindowsDuration = log\n    .filter { it.os == OS.WINDOWS }\n    .map(SiteVisit::duration)\n    .average()</code>\n        </deckgo-highlight-code>\n<ul>\n<li>윈도우 사용자의 평균 방문 시간 출력은 average 함수로 쉽게 표현할 수 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun List&lt;SiteVisit&gt;.averageDurationFor(os: OS) = filter { it.os == os }.map(SiteVisit::duration).average()</code>\n        </deckgo-highlight-code>\n<ul>\n<li>중복을 피하기 위해 OS를 파라미터로 뽑아낼 수 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun List&lt;SiteVisit&gt;.averageDurationFor(predicate: (SiteVisit) -&gt; Boolean) = filter(SiteVisit).map(SiteVisit::duration).average()</code>\n        </deckgo-highlight-code>\n<ul>\n<li>코드 중복을 줄일 때 함수 타입이 상당히 도움이 된다.</li>\n</ul>\n<h2 id=\"-102-인라인-함수를-사용해-람다의-부가-비용-없애기\" style=\"position:relative;\"><a href=\"#-102-%EC%9D%B8%EB%9D%BC%EC%9D%B8-%ED%95%A8%EC%88%98%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%B4-%EB%9E%8C%EB%8B%A4%EC%9D%98-%EB%B6%80%EA%B0%80-%EB%B9%84%EC%9A%A9-%EC%97%86%EC%95%A0%EA%B8%B0\" aria-label=\" 102 인라인 함수를 사용해 람다의 부가 비용 없애기 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 10.2 인라인 함수를 사용해 람다의 부가 비용 없애기</h2>\n<ul>\n<li>inline 변경자를 어떤 함수에 붙이면 컴파일러는 그 함수가 쓰이는 위치에 함수 호출을 생성하는 대신에 함수를 구현하는 코드로 바꿔치기 해준다.</li>\n</ul>\n<h3 id=\"-1021-인라이닝이-작동하는-방식\" style=\"position:relative;\"><a href=\"#-1021-%EC%9D%B8%EB%9D%BC%EC%9D%B4%EB%8B%9D%EC%9D%B4-%EC%9E%91%EB%8F%99%ED%95%98%EB%8A%94-%EB%B0%A9%EC%8B%9D\" aria-label=\" 1021 인라이닝이 작동하는 방식 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 10.2.1 인라이닝이 작동하는 방식</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">inline fun &lt;T&gt; synchronized(lock: Lock, action: () -&gt; T): T {\n    lock.lock()\n    try {\n        return action()\n    }\n    finally {\n        lock.unlock()\n    }\n}\n\nfun main() {\n    val l = ReentrantLock()\n    synchronized(1) {\n        // ...\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>어떤 함수를 inline으로 선언하면 그 함수의 본문이 인라인된다.\n<ul>\n<li>함수를 호출하는 코드를 함수를 호출하는 바이트코드 대신에 함수 본문을 번역한 바이트코드로 컴파일한다는 뜻</li>\n</ul>\n</li>\n<li>synchronized 함수를 inline으로 선언했으므로 synchronized를 호출하는 코드는 모두 자바의 synchronized 문과 같아진다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class LockOwner(val lock: Lock) {\n    fun runUnderLock(body: () -&gt; Unit) {\n        synchronized(lock, body)\n    } \n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>인라인 함수를 호출하면서 람다를 넘기는 대신에 함수 타입의 변수를 넘길 수도 있다.</li>\n<li>함수에 더해 프로퍼티 접근자에도 inline을 붙일 수 있다.</li>\n</ul>\n<h3 id=\"-1022-인라인-함수의-제약\" style=\"position:relative;\"><a href=\"#-1022-%EC%9D%B8%EB%9D%BC%EC%9D%B8-%ED%95%A8%EC%88%98%EC%9D%98-%EC%A0%9C%EC%95%BD\" aria-label=\" 1022 인라인 함수의 제약 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 10.2.2 인라인 함수의 제약</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class FunctionStorage {\n    var myStoredFunction: ((Int) -&gt; Unit)? = null\n    inline fun storeFunction(f: (Int) -&gt; Unit) { \n        myStoredFunction = f // error\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>함수가 인라이닝될 때 그 함수에 인자로 전달된 람다식의 본문은 결과 코드에 직접 들어갈 수 있다. 하지만 이렇게 람다가 본문에 직접 펼쳐지기 때문에 함수가 파라미터로 전달받은 람다를 본문에 사용하는 방식이 한정될 수밖에 없다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun &lt;T, R&gt; Sequence&lt;T&gt;.map(transform: (T) -&gt; R): Sequence&lt;R&gt; {\n    return TransformingSequence(this, transform)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>Sequence.map 의 정의다.</li>\n<li>transform 파라미터로 전달받은 함수 값을 호출하지 않는 대신, TransformingSequence라는 클래스의 생성자에게 그 함수 값을 넘긴다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">inline fun foo(inlined: () -&gt; Unit, noinline notInlined: () -&gt; Unit) {\n    //..\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>인라이닝하면 안 되는 람다를 파라미터로 받는다면 noinline 변경자를 파라미터 이름 앞에 붙여 인라이닝을 금지할 수 있다.</li>\n</ul>\n<h3 id=\"-1023-컬렉션-연산-인라이닝\" style=\"position:relative;\"><a href=\"#-1023-%EC%BB%AC%EB%A0%89%EC%85%98-%EC%97%B0%EC%82%B0-%EC%9D%B8%EB%9D%BC%EC%9D%B4%EB%8B%9D\" aria-label=\" 1023 컬렉션 연산 인라이닝 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 10.2.3 컬렉션 연산 인라이닝</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">data class Person(val name: String, val age: Int)\n\nval people = listOf(Person(&quot;Alice&quot;, 29), Person(&quot;Bob&quot;, 31))\n\nfun main() {\n    println(people.filter { it.age &lt; 30 })\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>위 예제를 람다식을 사용하지 않게 다시 쓰면 아래와 같다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val result = mutableListOf&lt;Person&gt;()\n    for (person in people) {\n        if (person.age &lt; 30) {\n            result.add(person)\n        }\n    }\n    println(result)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>코틀린에서 filter는 인라인 함수다.</li>\n<li>즉, filter를 써서 생긴 바이트코드와 위 예제는 거의 같다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    println(\n        people.filter { it.age &lt; 30 }\n            .map(Person::name)\n    )\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>map도 인라인 함수다.</li>\n<li>시퀀스에 사용된 람다는 인라이닝되지 않는다. 따라서 지연 계산을 통해 성능을 향상시키려는 이유로 모든 컬렉션 연산에 asSequence를 붙이려고 해서는 안 된다.</li>\n<li>시퀀스를 통해 성능을 향상시킬 수 있는 경우는 컬렉션 크기가 큰 경우뿐이다.</li>\n</ul>\n<h3 id=\"-1024-언제-함수를-인라인으로-선언할지-결정\" style=\"position:relative;\"><a href=\"#-1024-%EC%96%B8%EC%A0%9C-%ED%95%A8%EC%88%98%EB%A5%BC-%EC%9D%B8%EB%9D%BC%EC%9D%B8%EC%9C%BC%EB%A1%9C-%EC%84%A0%EC%96%B8%ED%95%A0%EC%A7%80-%EA%B2%B0%EC%A0%95\" aria-label=\" 1024 언제 함수를 인라인으로 선언할지 결정 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 10.2.4 언제 함수를 인라인으로 선언할지 결정</h3>\n<ul>\n<li>inline 키워드를 사용해도 람다를 인자로 받는 함수만 성능이 좋아질 가능성이 높다.</li>\n<li>일반 함수 호출의 경우 JVM은 이미 강력하게 인라이닝을 지원한다.\n<ul>\n<li>바이트코드를 실제 기계어 코드로 번역하는 과정(JIT)에서 일어난다.</li>\n</ul>\n</li>\n<li>바이트코드에서는 각 함수 구현이 정확히 한 번만 있으면 되고 그 함수를 호출하는 모든 부분에 따로 코드를 중복할 필요가 없다. 반면, 코틀린 인라인 함수는 코드 중복이 생긴다.</li>\n<li>람다를 인자로 받는 함수를 인라이닝하면 이익이 더 많다.\n<ul>\n<li>함수 호출 비용 감소</li>\n<li>람다를 표현하는 클래스와 람다 인스턴스에 해당하는 객체를 만들 필요도 없어진다.</li>\n<li>JVM은 함수 호출과 람다를 인라이닝해줄 정도로 똑똑하지 못하다.</li>\n<li>추가 기능을 사용할 수 있다.</li>\n</ul>\n</li>\n<li>inline 변경자를 함수에 붙일 때는 코드 크기에 주의를 기울여야 한다.</li>\n</ul>\n<h3 id=\"-1025-withlock-use-uselines로-자원-관리를-위해-인라인된-람다-사용\" style=\"position:relative;\"><a href=\"#-1025-withlock-use-uselines%EB%A1%9C-%EC%9E%90%EC%9B%90-%EA%B4%80%EB%A6%AC%EB%A5%BC-%EC%9C%84%ED%95%B4-%EC%9D%B8%EB%9D%BC%EC%9D%B8%EB%90%9C-%EB%9E%8C%EB%8B%A4-%EC%82%AC%EC%9A%A9\" aria-label=\" 1025 withlock use uselines로 자원 관리를 위해 인라인된 람다 사용 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 10.2.5 withLock, use, useLines로 자원 관리를 위해 인라인된 람다 사용</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">val l: Lock = ReentrantLock()\nl.withLock {\n    //..\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>withLock은 락을 획득한 후 작업하는 숙어를 별도의 함수로 분리</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun readFirstLineFromFile(fileName: String): String {\n    BufferedReader(FileReader(fileName)).use { br -&gt;\n        return br.readLine()\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>use 함수는 닫을 수 있는 자원에 대해 호출하는 확장 함수다.\n<ul>\n<li>람다를 호출하고 사용 후 자원이 확실히 닫히게 한다.</li>\n</ul>\n</li>\n<li>use 함수는 인라인 함수이며, 성능에는 영향이 없다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun readFirstLineFromFile(fileName: String): String {\n    Path(fileName).useLines { \n        return it.first()\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>use는 Closeable과 함께 쓰이지만 useLines는 File과 Path 객체에 정의돼 있고, 람다가 문자열 시퀀스에 접근하게 해준다.</li>\n</ul>\n<h2 id=\"-103-람다에서-반환-고차-함수에서-흐름-제어\" style=\"position:relative;\"><a href=\"#-103-%EB%9E%8C%EB%8B%A4%EC%97%90%EC%84%9C-%EB%B0%98%ED%99%98-%EA%B3%A0%EC%B0%A8-%ED%95%A8%EC%88%98%EC%97%90%EC%84%9C-%ED%9D%90%EB%A6%84-%EC%A0%9C%EC%96%B4\" aria-label=\" 103 람다에서 반환 고차 함수에서 흐름 제어 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 10.3 람다에서 반환: 고차 함수에서 흐름 제어</h2>\n<h3 id=\"-1031-람다-안의-return-문-람다를-둘러싼-함수에서-반환\" style=\"position:relative;\"><a href=\"#-1031-%EB%9E%8C%EB%8B%A4-%EC%95%88%EC%9D%98-return-%EB%AC%B8-%EB%9E%8C%EB%8B%A4%EB%A5%BC-%EB%91%98%EB%9F%AC%EC%8B%BC-%ED%95%A8%EC%88%98%EC%97%90%EC%84%9C-%EB%B0%98%ED%99%98\" aria-label=\" 1031 람다 안의 return 문 람다를 둘러싼 함수에서 반환 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 10.3.1 람다 안의 return 문: 람다를 둘러싼 함수에서 반환</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">data class Person(val name: String, val age: Int)\n\nval people = listOf(Person(&quot;Alice&quot;, 29), Person(&quot;Bob&quot;, 31))\n\nfun lookForAlice(people: List&lt;Person&gt;) {\n    for (person in people) {\n        if (person.name == &quot;Alice&quot;) {\n            println(&quot;Found!&quot;)\n            return\n        }\n    }\n    println(&quot;Alice is not found&quot;)\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun lookForAlice(people: List&lt;Person&gt;) {\n    people.forEach {\n        if (it.name == &quot;Alice&quot;) {\n            println(&quot;Found!&quot;)\n            return\n        }\n    }\n    println(&quot;Alice is not found&quot;)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>위 두 예제는 같은 의미다.</li>\n<li>람다 안에서 return을 사용하면 람다에서만 반환되는 것이 아니라 그 람다를 호출하는 함수가 실행을 끝내고 반환된다.</li>\n<li>비로컬 return: 자신을 둘러쌓고 있는 블록보다 더 바깥에 있는 다른 블록을 반환하게 만드는 return 문</li>\n<li>return이 바깥쪽 함수를 반환시킬 수 있는 때는 람다를 인자로 받는 함수가 인라인 함수인 경우다.\n<ul>\n<li>인라이닝되지 않는 함수에 전달되는 람다 안에서 return을 사용할 수는 없다.</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"-1032-람다로부터-반환-레이블을-사용한-return\" style=\"position:relative;\"><a href=\"#-1032-%EB%9E%8C%EB%8B%A4%EB%A1%9C%EB%B6%80%ED%84%B0-%EB%B0%98%ED%99%98-%EB%A0%88%EC%9D%B4%EB%B8%94%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%9C-return\" aria-label=\" 1032 람다로부터 반환 레이블을 사용한 return permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 10.3.2 람다로부터 반환: 레이블을 사용한 return</h3>\n<ul>\n<li>로컬 return: 람다의 실행을 끝내고 람다를 호출했던 코드의 실행을 계속 이어간다.</li>\n<li>로컬 return과 비로컬 return을 구분하기 위해 레이블을 사용한다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun lookForAlice(people: List&lt;Person&gt;) {\n    people.forEach label@{\n        if (it.name != &quot;Alice&quot;) return@label\n        println(&quot;Found Alice&quot;)\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>return으로 실행을 끝내고 싶은 람다식 앞에 레이블을 붙인다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun lookForAlice(people: List&lt;Person&gt;) {\n    people.forEach {\n        if (it.name != &quot;Alice&quot;) return@forEach\n        println(&quot;Found Alice!&quot;)\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>람다식의 레이블을 명시하면 함수 이름을 레이블로 사용할 수 없다는 점에 유의</li>\n</ul>\n<h3 id=\"-1033-익명-함수-기본적으로-로컬-return\" style=\"position:relative;\"><a href=\"#-1033-%EC%9D%B5%EB%AA%85-%ED%95%A8%EC%88%98-%EA%B8%B0%EB%B3%B8%EC%A0%81%EC%9C%BC%EB%A1%9C-%EB%A1%9C%EC%BB%AC-return\" aria-label=\" 1033 익명 함수 기본적으로 로컬 return permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 10.3.3 익명 함수: 기본적으로 로컬 return</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun lookForAlice(people: List&lt;Person&gt;) {\n    people.forEach (fun (person) {\n        if (person.name == &quot;Alice&quot;) return\n        println(&quot;${person.name} is not Alice&quot;)\n    })\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>return은 가장 가까운 함수를 가리킨다.</li>\n<li>익명 함수 안에서 레이블이 붙지 않은 return 식은 익명 함수 자체를 반환시킬 뿐 익명 함수를 둘러싼 다른 함수를 반환시키지 않는다.</li>\n<li>익명 함수는 일반 함수와 비슷해 보이지만 실제로는 람다식에 대한 문법적 편의일 뿐이다.</li>\n</ul>","excerpt":"📖 10.1 다른 함수를 인자로 받거나 반환하는 함수 정의: 고차 함수 고차 할수는 다른 할수를 인자로 받거나 함수를 반환하는 합수 코물린에서는 다나 할수 참조를 사용해 함수를 값으로 표현할 수 있다. 표준 라이브러리 함수인 filter는 술어 함수를 인자로 받으므로 고차 함수 🔖 10.1.1 함수 타입은 람다의 파라미터 타입과 반환 타입을 지정한다 컴파일러는 sum과 action…","fields":{"slug":"/backend/kotlin-in-action/10장-고차함수-람다를_파라미터와_반환값으로_사용/"},"frontmatter":{"title":"Kotlin in Action - 10장 고차 함수: 람다를 파라미터와 반환값으로 사용","thumbnail":{"childImageSharp":{"fluid":{"src":"/static/f7f7ddfa31d1614405dc5af1487b9ec4/9c94d/kotlin-in-action.png"}}},"draft":false,"category":"Back-End","tags":["Kotlin"],"date":"May 11, 2025"}}}},"staticQueryHashes":["2374173507","2996537568","3691437124"]}