![[Kotlin] 기본 문법 - Basic types, Collections, 조건문, 반복문](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbWyow%2FbtsMfitYdtC%2FIpGMqThHtAU20vfsmapxXK%2Fimg.png)
안녕하세요. 저는 2년차 백엔드 개발자입니다.
현재 JS(TS)로 개발하고 있고, Java는 코테용 언어로 사용하고 있습니다.
코틀린을 사용하기 위해 현재 제가 알고 있는 지식 대비 필요 부분들만 학습하여 정리하는 Kotlin 시리즈입니다.
피드백은 언제나 감사합니다!!
Kotlin 등장 배경
내가 사용하고 있는 Nest는 nodejs의 구조적인 한계를 해결하기 위해 등장했으며 모듈 기반 아키텍처와 의존성 주입과 같은 개념을 적극 도입함으로써 nodejs의 자유도가 높은 구조를 개선하고 엔터프라이즈급 애플리케이션에서도 일관된 개발 경험을 제공하기 위해 만들어진 프레임워크이다.
코틀린의 공식 문서에는, 간결하고 안전하며 Java와 100% 호환이 되고 (JVM 위에서 동작) NullSafety하다는 특징을 Introduce에 서술해두었다. 이 밖에도 코틀린이 등장한 배경이라던가, 해결하고자 하는 문제가 무엇이었는지 찾아보고 싶어 찾아봤고, 기존의 자바에서 어떤 문제가 있었는지는 직접 자바로 서버 구축을 하고 유지 보수를 해보지 않아서, 정리된 글들을 가져왔다.
나는 이 수많은 이유들 중에 안드로이드 앱을 여러 개 출시할 계획으로 코틀린 공부를 시작한다.
현재 사용중인 RN / Node(Nest)를 통해 개발을 하면 훨씬 생산성이 향상되겠지만, 익숙함을 잠시 내려놓고 개인적인 개발을 할 때는 새로운 환경에서 다시 시작해보려한다.
Take Kotlin Tour
공식 문서의 기본 가이드에 간단히 나와있는 언어의 핵심 개념 페이지들을 하나씩 읽어보며 공부한 내용들을 정리해보았다. 내용이 너무 길어져서, Functions (+ Lamda), Classes, Null Safety는 다음 포스팅에 정리해서 총 2회분의 포스팅을 통해 문법을 정리하려고 한다.
Variable
JS의 let, const처럼 mutable하고 immutable한 키워드인 var, val을 통해 변수 선언을 할 수 있다.
// Immutable variable ( == const )
val test1 = 10
test1 = 5 // ❌ Val cannot be reassigned
// Mutable variable ( == let )
var test2 = "test" // 타입 추론 (test2: String)
test2 = 1 // ❌ Type Error (정수 리터럴이 String과 호환되지 않음)
tet2 = "TEST2" // ✅
// 객체의 멤버 변수에서 `val`은 readonly처럼 동작
data class User(var name: String, val age: Int)
val user = User("mag1c", 30)
user.name = "mag2c" // ✅ 변경 가능
user.age = 20 // ❌ 변경 불가능
val list = mutableListOf(1, 2, 3)
list.add(4) // ✅ 가능 (리스트 내부 값 변경 가능)
list = mutableListOf(5, 6, 7) // ❌ 오류 (val 자체는 변경 불가능)
Basic Types
TS처럼 자료형을 콜론(:)을 이용해 명시할 수도, 생략할 수도 있다. 마찬가지로 TS처럼 타입 추론을 자동으로 할 수 있기 때문에 굳이 명시하지 않아도 된다. 신기한 부분은, Unsigned Integers를 지원한다는 점이었다.
Basic Types | 예시 | |
Integers | Byte, Short, Int, Long | val year: Int = 2020 |
Unsigned integers | UByte, UShort, UInt, ULong | val score: UInt = 100u |
Floating-point numbers | Float, Double | val currentTemp: Float = 24.5f, val price: Double = 19.99 |
Booleans | Boolean | val isEnabled: Boolean = true |
Characters | Char | val separator: Char = ',' |
Strings | String | val message: String = "Hello, world!" |
Any | Any | val anything: Any = "HELLO" |
Any 타입은 모든 타입의 부모 타입(super type)이다. 기본적으로 모든 값이 될 수 있다. TS의 any와 유사하지만 코틀린에서의 Any 타입은 nullable하지 않다. 옵셔널 연산자인 ?을 통해 nullable을 명시할 수 있다.
//TS
let value: any; // undefined
value = 42; // ✅
value = null; // ✅
//Kotlin
var value: Any = "HELLO"
value = 42 // ✅
value = null // ❌
var value: Any? = "HELLO"
value = 42 // ✅
value = null // ✅
Type Check
is를 통한 타입 체크도 가능한데, TS의 typeof와 유사하게 동작한다. 다만 TS의 typeof는 object 타입이 어떤 객체인지까지는 명시해주지 않지만, is를 사용하게되면 instanceof 처럼 동작한다는 점이다.
// is를 통한 타입 체크가 가능
val string1 = "string1"
val isString = if (string1 is String) true else false
print(isString)
또한 TS에 있는 as를 통한 명시적 형변환도 코틀린에서 가능하다.
// casting
val obj: Any = "Hello"
val str: String = obj as String // ✅ 명시적 형 변환
println(str.length) // 5
// null-safe한 casting
val obj: Any? = null
val str: String? = obj as? String // ✅ 안전한 형 변환 (null 반환 가능)
String Templates
JS의 Template literals과 유사하지만, 코틀린의 문법이 조금 더 편리하다고 느꼈다. JS에서는 항상 중괄호로 감싸주어야했지만, 코틀린에서는 달러 기호($) 하나면 끝이다.
// JS
let name = "mag1c"
let message = "HELLO"
function sendMessage(name, message) {
console.log(`[${name}] ${message}`);
}
val name = "mag1c"
val message = "HELLO"
fun sendMessage(name: String, message: String) {
println("[$name] $message")
}
Collections
기본적으로 List, Set, Map을 지원한다. 아래는 코틀린의 기본적인 Collections 구조이다.
기본적으로 JS의 Iterable과 같은 개념으로 보인다. forEach, iterator, hasNext등을 사용할 수 있고, 이런 내장 메서드를 통해 요소를 순회할 수 있다. 반대로 MutableIterable은 Iterable을 상속하지만, mutable한 요소를 구현하여 쓰기 작업을 가능하게 한다.
// Iterable<T>
val list: Iterable<Int> = listOf(1, 2, 3)
for (item in list) {
println(item)
}
// MutableIterable<T>
val list = mutableListOf(1, 2, 3)
val iterator = list.iterator()
while (iterator.hasNext()) {
if (iterator.next() == 2) {
iterator.remove() // ✅ 요소 제거 가능
}
}
println(list) // [1, 3]
// Collection<T>
val collection: Collection<Int> = listOf(1, 2, 3)
println(collection.size) // ✅ 크기 확인 가능
println(collection.contains(2)) // ✅ 특정 요소 포함 여부 확인 가능
collection.add(4) // ❌ (Collection<T>에는 add() 없음)
// MutableCollection<T>
val mutableCollection: MutableCollection<Int> = mutableListOf(1, 2, 3)
mutableCollection.add(4) // ✅ 가능
mutableCollection.remove(1) // ✅ 가능
Map은 Iterator의 특성인 순회를 전제로 하지 않기 떄문에 독립적인 Collections을 구현한 것으로 보인다. 여튼 콜렉션 구현을 위한 인터페이스는 동일하다.
// List
val fruits = listOf("apple", "banana", "orange") // immutable
val myDoggies = mutableListOf("guzzi", "coco") // mutable
// Set
val fruits = setOf("apple", "banana", "orange") // immutable
val myDoggies = mutableSetOf("guzzi", "coco") // mutable
// Map
val fruits = mapOf("apple" to 100, "banana" to 200, "orange" to 300) // immutable
val myDoggies = mutableMapOf("guzzi" to 1, "coco" to 2) // mutable
기본적으로 in 연산자도 지원하는 것으로 보인다.
println("apple" in fruits) //true
고차 함수(?)
JS의 map(), filter() 등의 Array.prototype에 있는 고차 함수들을 List, Set에서도 사용이 가능했다.
// map
val numbers = listOf(1, 2, 3)
val squared = numbers.map { it * it }
println(squared) // [1, 4, 9]
// filter
val numbers = listOf(1, 2, 3, 4, 5)
val evens = numbers.filter { it % 2 == 0 }
println(evens) // [2, 4]
// forEach
val numbers = listOf(1, 2, 3)
numbers.forEach { println(it) } // 1 2 3
// reduce
val numbers = listOf(1, 2, 3, 4)
val sum = numbers.reduce { acc, num -> acc + num }
println(sum) // 10
// flatMap
val arr = listOf(listOf(1, 2), listOf(3, 4))
val flattened = arr.flatMap { it }
println(flattened) // [1, 2, 3, 4]
Control Flow
조건문
IF문이나 WHEN문을 통해 조건문을 작성할 수 있으며, 공식 문서에 따르면 둘 중 하나를 선택하여 사용해야한다면 WHEN이 가독성, 유지보수, 확장성 측면에서 낫다고 설명하고 있다.
val trafficLightState = "Red"
var action: String
// if
if (trafficLightState === "Green") {
action = "GO"
}
if (trafficLightState === "Yellow") {
action = "SLOW DOWN"
}
if (trafficLightState === "Red") {
action = "STOP"
}
// when
val action2 = when (trafficLightState){
"Green" -> "GO"
"Yellow" -> "SLOW DOWN"
"Red" -> "STOP"
else -> "?"
}
반복문
// Range 표현
1..4 // 1, 2, 3, 4
1..<4 // 1, 2, 3
4 downTo 1 // 4, 3, 2, 1
4..1 // ❌
1..5 step 2 // 1, 3, 5
'a'..'d' // a, b, c, d
'z' downTo 's' // z, y, x, ..., s
// for
for (number in 1..5) {}
val array = IntArray(10) { 0 }
for (elem in array) {} // array 내부 요소를 하나씩 선택해서 순회
// while
while(true) { return }
// do while
var num = 0
do {
println("TEST")
num++
} while (num < 3)
References
2023.04 ~ 백엔드 개발자의 기록
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!