이 Codelab은 프로그래머를 위한 Kotlin 부트캠프 과정의 일부입니다. Codelab을 순서대로 진행하면 이 과정의 학습 효과를 극대화할 수 있습니다. 기존 지식에 따라 일부 섹션을 훑어볼 수도 있습니다. 이 과정은 객체 지향 언어를 알고 Kotlin을 배우고 싶은 프로그래머를 대상으로 합니다.
소개
Kotlin 부트캠프의 마지막 Codelab입니다. 이 Codelab에서는 주석과 라벨 지정 break에 관해 알아봅니다. Kotlin의 핵심 부분인 람다와 고차 함수를 검토합니다. 또한 인라인 함수와 단일 추상 메서드 (SAM) 인터페이스에 관해 자세히 알아봅니다. 마지막으로 Kotlin 표준 라이브러리에 관해 자세히 알아봅니다.
이 과정의 강의는 단일 샘플 앱을 빌드하는 대신 지식을 쌓을 수 있도록 설계되었지만, 서로 반독립적이므로 잘 아는 섹션은 대충 훑어볼 수 있습니다. 이러한 요소를 연결하기 위해 많은 예에서 수족관 테마를 사용합니다. 전체 수족관 스토리를 확인하려면 프로그래머를 위한 Kotlin 부트캠프 Udacity 과정을 확인하세요.
기본 요건
- Kotlin 함수, 클래스, 메서드의 문법
- IntelliJ IDEA에서 새 클래스를 만들고 프로그램을 실행하는 방법
- 람다 및 고차 함수의 기본사항
학습할 내용
- 주석의 기본사항
- 라벨이 지정된 섹션 나누기 사용 방법
- 고차 함수에 관한 추가 정보
- 단일 추상 메서드 (SAM) 인터페이스 정보
- Kotlin 표준 라이브러리 정보
실습할 내용
- 간단한 주석을 만듭니다.
- 라벨이 지정된 나누기를 사용합니다.
- Kotlin의 람다 함수를 검토합니다.
- 고차 함수를 사용하고 만듭니다.
- 단일 추상 메서드 인터페이스를 호출합니다.
- Kotlin 표준 라이브러리의 일부 함수를 사용합니다.
주석은 코드에 메타데이터를 첨부하는 방법이며 Kotlin에만 해당하는 것은 아닙니다. 주석은 컴파일러가 읽고 코드를 생성하거나 로직을 생성하는 데 사용됩니다. Ktor, Kotlinx와 같은 많은 프레임워크와 Room은 주석을 사용하여 코드를 실행하고 코드와 상호작용하는 방식을 구성합니다. 프레임워크를 사용하기 전에는 주석을 접할 일이 거의 없지만 주석을 읽는 방법을 알아두면 유용합니다.
Kotlin 표준 라이브러리를 통해 사용할 수 있으며 코드 컴파일 방식을 제어하는 주석도 있습니다. Kotlin을 Java 코드로 내보내는 경우에 유용하지만 그 외에는 자주 필요하지 않습니다.
주석은 주석이 달린 항목 바로 앞에 배치되며 클래스, 함수, 메서드, 제어 구조 등 대부분의 항목에 주석을 달 수 있습니다. 일부 주석은 인수를 사용할 수 있습니다.
다음은 주석의 예입니다.
@file:JvmName("InteropFish")
class InteropFish {
companion object {
@JvmStatic fun interop()
}
}이 파일의 내보낸 이름은 JvmName 주석이 있는 InteropFish입니다. JvmName 주석은 "InteropFish" 인수를 사용합니다. 컴패니언 객체에서 @JvmStatic는 Kotlin에 InteropFish에서 interop()을 정적 함수로 만들라고 지시합니다.
자체 주석을 만들 수도 있지만 이는 런타임에 클래스에 관한 특정 정보가 필요한 라이브러리(즉 리플렉션)를 작성하는 경우에 주로 유용합니다.
1단계: 새 패키지 및 파일 만들기
- src 아래에 새 패키지
example를 만듭니다. - example에서 새 Kotlin 파일
Annotations.kt를 만듭니다.
2단계: 자체 주석 만들기
Annotations.kt에서trim()및fertilize()의 두 메서드가 있는Plant클래스를 만듭니다.
class Plant {
fun trim(){}
fun fertilize(){}
}- 클래스의 모든 메서드를 출력하는 함수를 만드세요.
::class를 사용하여 런타임에 클래스에 관한 정보를 가져옵니다.declaredMemberFunctions를 사용하여 클래스의 메서드 목록을 가져옵니다. (이 기능을 사용하려면kotlin.reflect.full.*을 가져와야 합니다.)
import kotlin.reflect.full.* // required import
class Plant {
fun trim(){}
fun fertilize(){}
}
fun testAnnotations() {
val classObj = Plant::class
for (m in classObj.declaredMemberFunctions) {
println(m.name)
}
}- 테스트 루틴을 호출하는
main()함수를 만듭니다. 프로그램을 실행하고 출력을 살펴봅니다.
fun main() {
testAnnotations()
}⇒ trim fertilize
- 간단한 주석
ImAPlant을 만듭니다.
annotation class ImAPlant이 코드는 주석이 추가되었다고만 표시할 뿐 다른 작업은 실행하지 않습니다.
Plant클래스 앞에 주석을 추가합니다.
@ImAPlant class Plant{
...
}- 클래스의 모든 주석을 인쇄하도록
testAnnotations()를 변경합니다.annotations를 사용하여 클래스의 모든 주석을 가져옵니다. 프로그램을 실행하고 결과를 관찰합니다.
fun testAnnotations() {
val plantObject = Plant::class
for (a in plantObject.annotations) {
println(a.annotationClass.simpleName)
}
}⇒ ImAPlant
testAnnotations()을 변경하여ImAPlant주석을 찾습니다.findAnnotation()를 사용하여 특정 주석을 찾습니다. 프로그램을 실행하고 결과를 관찰합니다.
fun testAnnotations() {
val plantObject = Plant::class
val myAnnotationObject = plantObject.findAnnotation<ImAPlant>()
println(myAnnotationObject)
}
⇒ @example.ImAPlant()
3단계: 타겟팅된 주석 만들기
주석은 게터 또는 세터를 타겟팅할 수 있습니다. 이러한 경우 @get: 또는 @set: 접두사를 사용하여 적용할 수 있습니다. 주석이 있는 프레임워크를 사용할 때 이 문제가 많이 발생합니다.
- 속성 게터에만 적용할 수 있는
OnGet와 속성 세터에만 적용할 수 있는OnSet라는 두 개의 주석을 선언합니다. 각각에@Target(AnnotationTarger.PROPERTY_GETTER)또는PROPERTY_SETTER을 사용합니다.
annotation class ImAPlant
@Target(AnnotationTarget.PROPERTY_GETTER)
annotation class OnGet
@Target(AnnotationTarget.PROPERTY_SETTER)
annotation class OnSet
@ImAPlant class Plant {
@get:OnGet
val isGrowing: Boolean = true
@set:OnSet
var needsFood: Boolean = false
}주석은 런타임과 컴파일 시간에 모두 항목을 검사하는 라이브러리를 만드는 데 매우 유용합니다. 하지만 일반적인 애플리케이션 코드는 프레임워크에서 제공하는 주석만 사용합니다.
Kotlin에는 흐름을 제어하는 여러 방법이 있습니다. 함수에서 이를 둘러싼 함수로 반환되는 return는 이미 살펴본 바 있습니다. break는 return와 유사하지만 루프에 사용됩니다.
Kotlin에서는 라벨이 지정된 break라는 기능을 사용하여 루프를 추가로 제어할 수 있습니다. 라벨이 지정된 break는 해당 라벨이 지정된 루프 바로 다음의 실행 지점으로 이동합니다. 이는 중첩된 루프를 처리할 때 특히 유용합니다.
Kotlin의 모든 표현식은 라벨로 표시할 수 있습니다. 라벨은 식별자 뒤에 @ 기호가 오는 형식입니다.
Annotations.kt에서 내부 루프에서 빠져나와 라벨이 지정된 중단을 사용해 보세요.
fun labels() {
outerLoop@ for (i in 1..100) {
print("$i ")
for (j in 1..100) {
if (i > 10) break@outerLoop // breaks to outer loop
}
}
}
fun main() {
labels()
}- 프로그램을 실행하고 출력을 살펴봅니다.
⇒ 1 2 3 4 5 6 7 8 9 10 11
마찬가지로 라벨이 지정된 continue를 사용할 수 있습니다. 라벨이 지정된 루프에서 벗어나는 대신 라벨이 지정된 continue는 루프의 다음 반복으로 진행됩니다.
람다는 이름이 없는 함수인 익명 함수입니다. 변수에 할당하고 함수와 메서드에 인수로 전달할 수 있습니다. 이러한 도구는 매우 유용합니다.
1단계: 간단한 람다 만들기
- IntelliJ IDEA에서 Tools > Kotlin > Kotlin REPL을 선택하여 REPL을 시작합니다.
dirty을 2로 나누는 계산을 실행하는 인수dirty: Int가 있는 람다를 만듭니다. 람다를 변수waterFilter에 할당합니다.
val waterFilter = { dirty: Int -> dirty / 2 }waterFilter를 호출하여 값 30을 전달합니다.
waterFilter(30)⇒ res0: kotlin.Int = 15
2단계: 필터 람다 만들기
- REPL에서 속성 하나(
name)가 있는 데이터 클래스Fish를 만듭니다.
data class Fish(val name: String)- 이름이 Flipper, Moby Dick, Dory인
Fish3개로 구성된 목록을 만듭니다.
val myFish = listOf(Fish("Flipper"), Fish("Moby Dick"), Fish("Dory"))- 'i' 글자가 포함된 이름을 확인하는 필터를 추가합니다.
myFish.filter { it.name.contains("i")}
⇒ res3: kotlin.collections.List<Line_1.Fish> = [Fish(name=Flipper), Fish(name=Moby Dick)]
람다 표현식에서 it는 현재 목록 요소를 나타내며 필터는 각 목록 요소에 순서대로 적용됩니다.
", "을 구분 기호로 사용하여 결과에joinString()을 적용합니다.
myFish.filter { it.name.contains("i")}.joinToString(", ") { it.name }
⇒ res4: kotlin.String = Flipper, Moby Dick
joinToString() 함수는 필터링된 이름을 지정된 문자열로 구분하여 연결하여 문자열을 만듭니다. Kotlin 표준 라이브러리에 내장된 유용한 함수 중 하나입니다.
람다 또는 기타 함수를 함수의 인수로 전달하면 고차 함수가 생성됩니다. 위의 필터가 간단한 예입니다. filter()는 함수이며 목록의 각 요소를 처리하는 방법을 지정하는 람다를 전달합니다.
확장 람다를 사용하여 고차 함수를 작성하는 것은 Kotlin 언어의 가장 고급 부분 중 하나입니다. 작성 방법을 배우는 데는 시간이 걸리지만 사용하기에는 매우 편리합니다.
1단계: 새 수업 만들기
- example 패키지 내에서 새 Kotlin 파일
Fish.kt를 만듭니다. Fish.kt에서 속성이 하나인name를 사용하여 데이터 클래스Fish를 만듭니다.
data class Fish (var name: String)- 함수
fishExamples()를 만듭니다.fishExamples()에서"splashy"이라는 물고기를 만듭니다(모두 소문자).
fun fishExamples() {
val fish = Fish("splashy") // all lowercase
}fishExamples()를 호출하는main()함수를 만듭니다.
fun main () {
fishExamples()
}main()왼쪽에 있는 녹색 삼각형을 클릭하여 프로그램을 컴파일하고 실행합니다. 아직 출력이 없습니다.
2단계: 고차 함수 사용
with() 함수를 사용하면 객체 또는 속성을 더 간결한 방식으로 하나 이상 참조할 수 있습니다. this 사용 with()는 실제로 고차 함수이며 람다에서 제공된 객체로 무엇을 할지 지정합니다.
with()을 사용하여fishExamples()의 물고기 이름을 대문자로 표시합니다. 중괄호 안에서this는with()에 전달된 객체를 나타냅니다.
fun fishExamples() {
val fish = Fish("splashy") // all lowercase
with (fish.name) {
this.capitalize()
}
}- 출력이 없으므로
println()를 추가합니다.this는 암시적이며 필요하지 않으므로 삭제해도 됩니다.
fun fishExamples() {
val fish = Fish("splashy") // all lowercase
with (fish.name) {
println(capitalize())
}
}⇒ Splashy
3단계: 고차 함수 만들기
내부적으로 with()는 고차 함수입니다. 이것이 어떻게 작동하는지 확인하려면 문자열에만 작동하는 with()의 매우 단순화된 버전을 직접 만들면 됩니다.
Fish.kt에서 두 개의 인수를 사용하는 함수myWith()를 정의합니다. 인수는 작업할 객체와 작업을 정의하는 함수입니다. 함수의 인수 이름 규칙은block입니다. 이 경우 함수는 아무것도 반환하지 않으며 이는Unit로 지정됩니다.
fun myWith(name: String, block: String.() -> Unit) {}이제 myWith() 내에서 block()이 String의 확장 함수입니다. 확장되는 클래스를 흔히 수신자 객체라고 합니다. 따라서 이 경우 name가 수신기 객체입니다.
myWith()본문에서 전달된 함수block()을 수신기 객체name에 적용합니다.
fun myWith(name: String, block: String.() -> Unit) {
name.block()
}fishExamples()에서with()를myWith()로 바꿉니다.
fun fishExamples() {
val fish = Fish("splashy") // all lowercase
myWith (fish.name) {
println(capitalize())
}
}fish.name은 이름 인수이고 println(capitalize())은 블록 함수입니다.
- 프로그램을 실행하면 이전과 동일하게 작동합니다.
⇒ Splashy
4단계: 더 많은 내장 확장 프로그램 살펴보기
with() 확장 프로그램 람다는 매우 유용하며 Kotlin 표준 라이브러리의 일부입니다. run(), apply(), let()도 유용하게 사용할 수 있습니다.
run() 함수는 모든 유형에서 작동하는 확장 프로그램입니다. 인수로 람다 하나를 사용하고 람다 실행 결과를 반환합니다.
fishExamples()에서fish에run()을 호출하여 이름을 가져옵니다.
fish.run {
name
}name 속성만 반환합니다. 이를 변수에 할당하거나 인쇄할 수 있습니다. 이 예는 속성에 액세스하면 되므로 실제로 유용한 예는 아니지만 run()는 더 복잡한 표현식에 유용할 수 있습니다.
apply() 함수는 run()와 비슷하지만 람다의 결과 대신 적용된 변경된 객체를 반환합니다. 이는 새로 생성된 객체에서 메서드를 호출하는 데 유용할 수 있습니다.
fish의 사본을 만들고apply()를 호출하여 새 사본의 이름을 설정합니다.
val fish2 = Fish(name = "splashy").apply {
name = "sharky"
}
println(fish2.name)
⇒ sharky
let() 함수는 apply()와 유사하지만 변경사항이 적용된 객체의 사본을 반환합니다. 이는 조작을 함께 연결하는 데 유용할 수 있습니다.
let()를 사용하여fish의 이름을 가져오고, 대문자로 변환하고, 다른 문자열을 연결하고, 결과의 길이를 가져오고, 길이에 31을 더한 다음 결과를 출력합니다.
println(fish.let { it.name.capitalize()}
.let{it + "fish"}
.let{it.length}
.let{it + 31})⇒ 42
이 예에서 it가 참조하는 객체 유형은 Fish, String, String, Int 순입니다.
let()를 호출한 후fish를 출력하면 변경되지 않은 것을 확인할 수 있습니다.
println(fish.let { it.name.capitalize()}
.let{it + "fish"}
.let{it.length}
.let{it + 31})
println(fish)⇒ 42 Fish(name=splashy)
람다와 고차 함수는 매우 유용하지만 람다는 객체라는 점을 알아야 합니다. 람다 표현식은 Function 인터페이스의 인스턴스이며, 이는 Object의 하위 유형입니다. 앞서 살펴본 myWith() 예를 생각해 보세요.
myWith(fish.name) {
capitalize()
}Function 인터페이스에는 람다 표현식을 호출하도록 재정의되는 invoke() 메서드가 있습니다. 긴 형식으로 작성하면 아래 코드와 비슷합니다.
// actually creates an object that looks like this
myWith(fish.name, object : Function1<String, Unit> {
override fun invoke(name: String) {
name.capitalize()
}
})일반적으로 객체를 만들고 함수를 호출하는 데 많은 오버헤드(메모리 및 CPU 시간)가 발생하지 않으므로 문제가 되지 않습니다. 하지만 어디에서나 사용하는 myWith()와 같은 항목을 정의하는 경우 오버헤드가 누적될 수 있습니다.
Kotlin은 컴파일러에 약간의 작업을 추가하여 런타임 중에 오버헤드를 줄이는 방법으로 inline를 제공합니다. (구체화된 유형에 대해 설명한 이전 강의에서 inline에 대해 간략하게 알아봤습니다.) 함수를 inline로 표시하면 함수가 호출될 때마다 컴파일러가 실제로 소스 코드를 변환하여 함수를 '인라인'합니다. 즉, 컴파일러는 람다 내부의 명령어로 람다를 대체하도록 코드를 변경합니다.
위 예의 myWith()이 inline로 표시된 경우:
inline myWith(fish.name) {
capitalize()
}직접 호출로 변환됩니다.
// with myWith() inline, this becomes
fish.name.capitalize()대규모 함수를 인라인하면 코드 크기가 증가하므로 myWith()와 같이 여러 번 사용되는 간단한 함수에 사용하는 것이 좋습니다. 앞서 알아본 라이브러리의 확장 함수는 inline로 표시되므로 추가 객체가 생성되는 것에 대해 걱정하지 않아도 됩니다.
단일 추상 메서드는 메서드가 하나 있는 인터페이스를 의미합니다. 자바 프로그래밍 언어로 작성된 API를 사용할 때 매우 일반적이므로 SAM이라는 약어가 있습니다. 단일 추상 메서드 run()이 있는 Runnable와 단일 추상 메서드 call()이 있는 Callable가 그 예입니다.
Kotlin에서는 SAM을 매개변수로 사용하는 함수를 항상 호출해야 합니다. 아래 예시를 사용해 보세요.
- example 내에서 Java 클래스
JavaRun를 만들고 다음을 파일에 붙여넣습니다.
package example;
public class JavaRun {
public static void runNow(Runnable runnable) {
runnable.run();
}
}Kotlin에서는 유형 앞에 object:를 붙여 인터페이스를 구현하는 객체를 인스턴스화할 수 있습니다. SAM에 매개변수를 전달하는 데 유용합니다.
Fish.kt에서object:를 사용하여Runnable를 만드는runExample()함수를 만듭니다. 객체는"I'm a Runnable"를 출력하여run()를 구현해야 합니다.
fun runExample() {
val runnable = object: Runnable {
override fun run() {
println("I'm a Runnable")
}
}
}- 생성한 객체를 사용하여
JavaRun.runNow()를 호출합니다.
fun runExample() {
val runnable = object: Runnable {
override fun run() {
println("I'm a Runnable")
}
}
JavaRun.runNow(runnable)
}main()에서runExample()를 호출하고 프로그램을 실행합니다.
⇒ I'm a Runnable
무언가를 출력하는 데 많은 작업이 필요하지만 SAM이 작동하는 방식을 보여주는 좋은 예입니다. 물론 Kotlin에서는 더 간단한 방법을 제공합니다. 객체 대신 람다를 사용하여 이 코드를 훨씬 더 간결하게 만들 수 있습니다.
runExample의 기존 코드를 삭제하고 람다를 사용하여runNow()를 호출하도록 변경한 후 프로그램을 실행합니다.
fun runExample() {
JavaRun.runNow({
println("Passing a lambda as a Runnable")
})
}
⇒ Passing a lambda as a Runnable
- 마지막 매개변수 호출 구문을 사용하여 더 간결하게 만들고 괄호를 없앨 수 있습니다.
fun runExample() {
JavaRun.runNow {
println("Last parameter is a lambda as a Runnable")
}
}⇒ Last parameter is a lambda as a Runnable
이것이 단일 추상 메서드(SAM)의 기본 사항입니다. Class.singleAbstractMethod { lambda_of_override } 패턴을 사용하여 한 줄의 코드로 SAM을 인스턴스화하고, 재정의하고, 호출할 수 있습니다.
이 과정에서는 Kotlin의 핵심 부분인 람다를 검토하고 고차 함수를 더 자세히 살펴봤습니다. 주석과 라벨 지정 break에 대해서도 알아봤습니다.
- 주석을 사용하여 컴파일러에 사항을 지정합니다. 예를 들면 다음과 같습니다.
@file:JvmName("Foo") - 라벨이 지정된 break를 사용하여 중첩된 루프 내부에서 코드가 종료되도록 합니다. 예를 들면 다음과 같습니다.
if (i > 10) break@outerLoop // breaks to outerLoop label - 람다는 고차 함수와 결합하면 매우 강력해질 수 있습니다.
- 람다는 객체입니다. 객체를 만들지 않으려면 함수를
inline로 표시하면 됩니다. 그러면 컴파일러가 람다의 콘텐츠를 코드에 직접 넣습니다. inline를 신중하게 사용해야 하지만 프로그램의 리소스 사용량을 줄이는 데 도움이 될 수 있습니다.- 단일 추상 메서드(SAM)는 일반적인 패턴이며 람다를 사용하면 더 간단해집니다. 기본 패턴은
Class.singleAbstractMethod { lamba_of_override }입니다. - Kotlin 표준 라이브러리는 여러 SAM을 비롯한 다양한 유용한 함수를 제공하므로 라이브러리에 포함된 내용을 알아두세요.
이 과정에서 다룬 내용 외에도 Kotlin에는 더 많은 기능이 있지만 이제 Kotlin 프로그램을 직접 개발할 수 있는 기본사항을 갖추었습니다. 이 표현력이 뛰어난 언어에 많은 기대를 걸고 계시기를 바랍니다. 특히 Java 프로그래밍 언어를 사용해 온 개발자라면 코드를 적게 작성하면서 더 많은 기능을 만들 수 있을 것입니다. Kotlin 전문가가 되는 가장 좋은 방법은 학습하면서 연습하는 것이므로 계속해서 Kotlin을 탐색하고 직접 학습하세요.
Kotlin 문서
이 과정의 주제에 관해 자세히 알아보거나 막히는 부분이 있다면 https://kotlinlang.org에서 시작하는 것이 좋습니다.
Kotlin 튜토리얼
https://try.kotlinlang.org 웹사이트에는 Kotlin Koans라는 풍부한 튜토리얼, 웹 기반 인터프리터, 예시가 포함된 전체 참고 문서 세트가 포함되어 있습니다.
Udacity 과정
이 주제에 관한 Udacity 과정을 보려면 프로그래머를 위한 Kotlin 부트캠프를 참고하세요.
IntelliJ IDEA
IntelliJ IDEA 문서는 JetBrains 웹사이트에서 확인할 수 있습니다.
Kotlin 표준 라이브러리
Kotlin 표준 라이브러리는 유용한 함수를 많이 제공합니다. 자체 함수나 인터페이스를 작성하기 전에 항상 표준 라이브러리를 확인하여 누군가 이미 작업을 저장했는지 확인하세요. 새 기능이 자주 추가되므로 가끔 다시 확인하세요.
Kotlin 튜토리얼
https://try.kotlinlang.org 웹사이트에는 Kotlin Koans라는 풍부한 튜토리얼, 웹 기반 인터프리터, 예시가 포함된 전체 참고 문서 세트가 포함되어 있습니다.
Udacity 과정
이 주제에 관한 Udacity 과정을 보려면 프로그래머를 위한 Kotlin 부트캠프를 참고하세요.
IntelliJ IDEA
IntelliJ IDEA 문서는 JetBrains 웹사이트에서 확인할 수 있습니다.
이 섹션에는 강사가 진행하는 과정의 일부로 이 Codelab을 진행하는 학생에게 출제할 수 있는 과제가 나열되어 있습니다. 다음 작업은 강사가 결정합니다.
- 필요한 경우 과제를 할당합니다.
- 과제 제출 방법을 학생에게 알립니다.
- 과제를 채점합니다.
강사는 이러한 추천을 원하는 만큼 사용할 수 있으며 적절하다고 생각되는 다른 과제를 출제해도 됩니다.
이 Codelab을 직접 진행하는 경우 이러한 과제를 자유롭게 사용하여 배운 내용을 테스트해 보세요.
질문에 답하세요
질문 1
Kotlin에서 SAM은 다음을 의미합니다.
▢ 안전한 인수 일치
▢ 간단한 액세스 방법
▢ 단일 추상 메서드
▢ 전략적 액세스 방법
질문 2
다음 중 Kotlin 표준 라이브러리 확장 함수가 아닌 것은 무엇인가요?
▢ elvis()
▢ apply()
▢ run()
▢ with()
질문 3
다음 중 Kotlin의 람다에 관한 설명으로 옳지 않은 것은 무엇인가요?
▢ 람다는 익명 함수입니다.
▢ 람다는 인라인되지 않는 한 객체입니다.
▢ 람다는 리소스 집약적이므로 사용해서는 안 됩니다.
▢ 람다는 다른 함수에 전달할 수 있습니다.
질문 4
Kotlin의 라벨은 식별자 다음에 다음이 붙어 표시됩니다.
▢ :
▢ ::
▢ @:
▢ @
축하합니다. 프로그래머를 위한 Kotlin 부트캠프 Codelab을 완료했습니다.
다른 Codelab 링크를 비롯한 과정 개요는 프로그래머를 위한 Kotlin 부트캠프: 과정에 오신 것을 환영합니다를 참고하세요.