summaryrefslogtreecommitdiffhomepage
path: root/ko-kr/kotlin-kr.html.markdown
blob: 1a29c798dd51e3fa185634237fb95878a7f3ef67 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
---
language: kotlin
contributors:
    - ["S Webber", "https://github.com/s-webber"]
translators: 
    - ["Alan Jeon", "https://github.com/skyisle"]
lang: ko-kr
filename: LearnKotlin-kr.kt
---

Kotlin 은 정적 타입 프로그래밍 언어로 JVM, 안드로이드, 브라우져를 지원하며 Java 와 100% 상호 운용이 가능합니다.
[자세한 내용은 다음을 참고하세요.](https://kotlinlang.org/)

```kotlin
// 한 줄짜리 주석은 // 로 시작합니다.
/*
여러 줄 주석은 이와 같이 표시합니다. 
*/

// "package" 예약어는 자바와 동일하게 사용됩니다.
package com.learnxinyminutes.kotlin

/*
Kotlin 프로그램의 진입점은 main 이라는 함수명으로 지정됩니다. 
이 함수에 명령행 인수가 배열로 전달됩니다.
*/
fun main(args: Array<String>) {
    /*
    값을 선언할때는 "var" 또는 "val"이 사용됩니다.
    "var"와는 다르게 "val"로 선언된 변수에는 값을 재할당 할 수 없습니다.
    */
    val fooVal = 10 // fooVal 에 다른 값을 다시 할당 할 수 없습니다.
    var fooVar = 10
    fooVar = 20 // fooVar 에는 선언 이후에도 다른 값을 할당 할 수 있습니다

    /*
    대부분의 경우, Kotlin 에서는 변수 타입을 판단할 수 있기때문에 명시적으로 지정해 주지 않을 수 있습니다.
    다음과 같이 변수의 타입을 명시적으로 지정할 수 있습니다.
    */
    val foo: Int = 7

    /*
    문자형은 Java와 비슷하게 표시될 수 있습니다.
    이스케이핑에는 백슬래시를 사용합니다.
    */
    val fooString = "My String Is Here!"
    val barString = "Printing on a new line?\nNo Problem!"
    val bazString = "Do you want to add a tab?\tNo Problem!"
    println(fooString)
    println(barString)
    println(bazString)

    /*
    Raw 문자열은 쌍따옴표 3개(""")로 표기합니다.
    Raw 문자열에는 줄바꿈이나 모든 다른 문자들을 사용할 수 있습니다. 
    */
    val fooRawString = """
fun helloWorld(val name : String) {
   println("Hello, world!")
}
"""
    println(fooRawString)

    /*
    문자열은 템플릿 표현식을 포함할 수 있습니다.
    템플릿은 달러 기호($)로 시작합니다. 
    */
    val fooTemplateString = "$fooString has ${fooString.length} characters"
    println(fooTemplateString)

    /*
    변수가 null 값을 가지려면 이를 명시적으로 선언해야 합니다.
    변수 선언시 타입에 ? 표시를 붙여 nullable 을 표시합니다.
    ?. 연산자를 사용해 nullable 변수에 접근합니다.
    ?: 연산자를 이용해서 변수 값이 null 일때 사용할 값을 지정합니다.
    */
    var fooNullable: String? = "abc"
    println(fooNullable?.length) // => 3
    println(fooNullable?.length ?: -1) // => 3
    fooNullable = null
    println(fooNullable?.length) // => null
    println(fooNullable?.length ?: -1) // => -1

    /*
    함수는 "fun" 예약어를 사용해 선언합니다.
    함수명 이후 괄호 안에 인자를 기술합니다.
    함수 인자에 기본 값을 지정할 수도 있습니다.
    함수에 리턴값이 있을 때, 필요한 경우 인자 뒤에 타입을 명시합니다.
    */
    fun hello(name: String = "world"): String {
        return "Hello, $name!"
    }
    println(hello("foo")) // => Hello, foo!
    println(hello(name = "bar")) // => Hello, bar!
    println(hello()) // => Hello, world!

    /*
    함수에 가변 인자를 넘기려면 인자에 "vararg" 예약어를 사용합니다. 
    */
    fun varargExample(vararg names: Int) {
        println("Argument has ${names.size} elements")
    }
    varargExample() // => 인자가 0개 인 경우
    varargExample(1) // => 인자가 1개인 경우
    varargExample(1, 2, 3) // => 인자가 3개인 경우

    /*
    함수가 단일 표현식으로 이루어진 경우에 중괄호를 생략할 수 있습니다.
    이때 함수 구현부는 = 기호 이후에 기술합니다.
    */
    fun odd(x: Int): Boolean = x % 2 == 1
    println(odd(6)) // => false
    println(odd(7)) // => true

    // 리턴 타입이 유추 가능한 경우 이를 명시하지 않아도 됩니다. 
    fun even(x: Int) = x % 2 == 0
    println(even(6)) // => true
    println(even(7)) // => false

    // 함수는 함수를 인자를 받을 수 있고 함수를 리턴할 수 있습니다. 
    fun not(f: (Int) -> Boolean): (Int) -> Boolean {
        return {n -> !f.invoke(n)}
    }
    // 함수는 :: 연산자를 사용해서 다른 함수에 인자로 넘길 수 있습니다. 
    val notOdd = not(::odd)
    val notEven = not(::even)
    // 람다식을 인자로 사용할 수 있습니다. 
    val notZero = not {n -> n == 0}
    /*
    하나의 인자를 가지는 람다식의 선언부와 -> 연산자는 생략될 수 있습니다.
    이때 그 인자명은 it로 지정됩니다.
    */
    val notPositive = not {it > 0}
    for (i in 0..4) {
        println("${notOdd(i)} ${notEven(i)} ${notZero(i)} ${notPositive(i)}")
    }

    // "class" 예약어는 클래스를 선언할 때 사용됩니다. 
    class ExampleClass(val x: Int) {
        fun memberFunction(y: Int): Int {
            return x + y
        }

        infix fun infixMemberFunction(y: Int): Int {
            return x * y
        }
    }
    /*
    새로운 객체를 생성하기 위해서는 생성자를 바로 호출합니다.
    Kotlin 에서는 new 예약어가 없다는 걸 기억하세요.
    */
    val fooExampleClass = ExampleClass(7)
    // 맴버 함수는 dot 표기로 호출할 수 있습니다. 
    println(fooExampleClass.memberFunction(4)) // => 11
    /*
    함수 선언에 "infix" 예약어를 사용하면 이 함수를 중위 표현식(infix notation)으로 호출할 수 있습니다 
    */
    println(fooExampleClass infixMemberFunction 4) // => 28

    /*
    데이터 클래스로 데이터만을 가지고 있는 클래스를 손쉽게 선언할 수 있습니다.
    "hashCode"/"equals" 와 "toString" 는 자동으로 생성됩니다.
    */
    data class DataClassExample (val x: Int, val y: Int, val z: Int)
    val fooData = DataClassExample(1, 2, 4)
    println(fooData) // => DataClassExample(x=1, y=2, z=4)

    // 데이터 클래스는 copy 함수를 가지고 있습니다. 
    val fooCopy = fooData.copy(y = 100)
    println(fooCopy) // => DataClassExample(x=1, y=100, z=4)

    // 객체를 여러 변수로 분리할 수 있습니다. 
    val (a, b, c) = fooCopy
    println("$a $b $c") // => 1 100 4
    
    // "for" 루프에서 변수 분리 하기 
    for ((a, b, c) in listOf(fooData)) {
        println("$a $b $c") // => 1 100 4
    }
    
    val mapData = mapOf("a" to 1, "b" to 2)
    // Map.Entry 또한 키와 값으로 분리가 가능합니다. 
    for ((key, value) in mapData) {
        println("$key -> $value")
    }

    // "with" 함수는 JavaScript 의 "with" 구문과 비슷하게 사용됩니다. 
    data class MutableDataClassExample (var x: Int, var y: Int, var z: Int)
    val fooMutableData = MutableDataClassExample(7, 4, 9)
    with (fooMutableData) {
        x -= 2
        y += 2
        z--
    }
    println(fooMutableData) // => MutableDataClassExample(x=5, y=6, z=8)

    /*
    "listOf" 함수로 리스트를 만들 수 있습니다.
    리스트는 변경 불가능(immutable)하게 만들어져 항목의 추가 삭제가 불가능합니다.
    */
    val fooList = listOf("a", "b", "c")
    println(fooList.size) // => 3
    println(fooList.first()) // => a
    println(fooList.last()) // => c
    // 각 항목은 인덱스로 접근이 가능합니다. 
    println(fooList[1]) // => b

    // 변경가능한(mutable) 리스트는 "mutableListOf" 함수로 만들 수 있습니다. 
    val fooMutableList = mutableListOf("a", "b", "c")
    fooMutableList.add("d")
    println(fooMutableList.last()) // => d
    println(fooMutableList.size) // => 4

    // 집합(set)은 "setOf" 함수로 만들 수 있습니다.
    val fooSet = setOf("a", "b", "c")
    println(fooSet.contains("a")) // => true
    println(fooSet.contains("z")) // => false

    // 맵은 "mapOf" 함수로 만들 수 있습니다.
    val fooMap = mapOf("a" to 8, "b" to 7, "c" to 9)
    // 맵은 키를 통해 그 값에 접근할 수 있습니다. Map values can be accessed by their key.
    println(fooMap["a"]) // => 8

    /*
    시퀀스는 지연 평가되는 컬랙션을 말합니다. Sequences represent lazily-evaluated collections.
    "generateSequence" 를 사용해 시퀀스를 만들 수 있습니다. We can create a sequence using the "generateSequence" function.
    */
    val fooSequence = generateSequence(1, { it + 1 })
    val x = fooSequence.take(10).toList()
    println(x) // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    // 다음은 시퀀스를 사용해서 피보나치 수열을 생성하는 예입니다.
    fun fibonacciSequence(): Sequence<Long> {
        var a = 0L
        var b = 1L

        fun next(): Long {
            val result = a + b
            a = b
            b = result
            return a
        }

        return generateSequence(::next)
    }
    val y = fibonacciSequence().take(10).toList()
    println(y) // => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

    // Kotlin 은 컬랙션에서 사용할 수 있는 고차(higher-order)함수를 제공합니다.
    val z = (1..9).map {it * 3}
                  .filter {it < 20}
                  .groupBy {it % 2 == 0}
                  .mapKeys {if (it.key) "even" else "odd"}
    println(z) // => {odd=[3, 9, 15], even=[6, 12, 18]}

    // "for" 루프는 이터레이터를 제공하는 어떤 것과도 함께 사용할 수 있습니다.
    for (c in "hello") {
        println(c)
    }

    // "while" 루프는 다른 언어들과 동일하게 사용됩니다.
    var ctr = 0
    while (ctr < 5) {
        println(ctr)
        ctr++
    }
    do {
        println(ctr)
        ctr++
    } while (ctr < 10)

    /*
    "if"는 값을 리턴하는 표현으로 사용될 수 있습니다.
    그래서 Kotlin 에서는 삼항 ?: 연산자가 필요하지 않습니다.
    */
    val num = 5
    val message = if (num % 2 == 0) "even" else "odd"
    println("$num is $message") // => 5 is odd

    // "when"은 "if-else if" 를 대체할때 사용할 수 있습니다.
    val i = 10
    when {
        i < 7 -> println("first block")
        fooString.startsWith("hello") -> println("second block")
        else -> println("else block")
    }

    // "when"은 인수와 함께 사용될 수 있습니다.
    when (i) {
        0, 21 -> println("0 or 21")
        in 1..20 -> println("in the range 1 to 20")
        else -> println("none of the above")
    }

    // "when"은 값을 리턴하는 함수처럼 사용될 수 있습니다.
    var result = when (i) {
        0, 21 -> "0 or 21"
        in 1..20 -> "in the range 1 to 20"
        else -> "none of the above"
    }
    println(result)

    /*
    객체가 어떤 타입인지를 확인하기 위해 "is" 연산자를 사용할 수 있습니다.
    타입 체크를 통과하면 객체의 명시적인 형변환 없이도 그 타입 값으로 사용될 수 있습니다.
    이를 스마트 변환(Smartcast)이라 부릅니다.
    */
    fun smartCastExample(x: Any) : Boolean {
        if (x is Boolean) {
            // x is automatically cast to Boolean
            return x
        } else if (x is Int) {
            // x is automatically cast to Int
            return x > 0
        } else if (x is String) {
            // x is automatically cast to String
            return x.isNotEmpty()
        } else {
            return false
        }
    }
    println(smartCastExample("Hello, world!")) // => true
    println(smartCastExample("")) // => false
    println(smartCastExample(5)) // => true
    println(smartCastExample(0)) // => false
    println(smartCastExample(true)) // => true

    // 스마트 변환은 when 블럭과도 함께 사용됩니다.
    fun smartCastWhenExample(x: Any) = when (x) {
        is Boolean -> x
        is Int -> x > 0
        is String -> x.isNotEmpty()
        else -> false
    }

    /*
    확장(Extensions)을 이용해 클래스에 새로운 기능을 추가할 수 있습니다.
    C#에서의 확장 매서드와 유사합니다.
    */
    fun String.remove(c: Char): String {
        return this.filter {it != c}
    }
    println("Hello, world!".remove('l')) // => Heo, word!

    println(EnumExample.A) // => A
    println(ObjectExample.hello()) // => hello
}

// Enum 클래스는 자바의 enum 타입과 유사합니다.
enum class EnumExample {
    A, B, C
}

/*
"object" 예약어는 싱클톤 객체를 생성할 때 사용됩니다. 
객체를 새로 생성할 수는 없지만 이름을 가지고 접근해 사용할 수 있습니다.
이는 스칼라의 싱글톤 객체와 유사합니다.
*/
object ObjectExample {
    fun hello(): String {
        return "hello"
    }
}

fun useObject() {
    ObjectExample.hello()
    val someRef: Any = ObjectExample // 객체의 이름을 그대로 사용합니다.
}
```

### 더 알아보기

* [Kotlin tutorials (EN)](https://kotlinlang.org/docs/tutorials/)
* [Try Kotlin in your browser (EN)](http://try.kotlinlang.org/)
* [A list of Kotlin resources (EN)](http://kotlin.link/)