with ChatGPT 시리즈는 ChatGPT의 내용과 개인의 생각을 토대로 학습해 보는 컨텐츠입니다.
Kotlin은 정적 타입(Statically Typed) 언어로, 변수의 타입을 명확하게 지정해야 하지만 타입 추론(Type Inference)을 통해 자동으로 타입을 결정할 수 있습니다.
이번 주제에서는 Kotlin의 기본 타입을 다루는 방법과 타입 추론이 중요한 이유를 알아보겠습니다.
🔥 1. 코틀린의 기본 타입 (Primitive Types)
Kotlin의 기본 타입은 Java의 원시 타입(Primitive Type)을 래핑 하는 구조가 아니라 객체(Object) 형태로 존재합니다. 하지만 컴파일러가 최적화하여 원시 타입으로 변환합니다.
✅ 기본 타입과 선언 방식
| 타입 | 크기 | 값 범위 | 예제 |
| Byte | 8-bit | -128 ~ 127 | val a: Byte = 100 |
| Short | 16-bit | -32,768 ~ 32,767 | val b: Short = 32000 |
| Int | 32-bit | -2³¹ ~ 2³¹-1 | val c: Int = 100000 |
| Long | 64-bit | -2⁶³ ~ 2⁶³-1 | val d: Long = 10000000000L |
| Float | 32-bit | 6~7 자리 소수 | val e: Float = 3.14F |
| Double | 64-bit | 15~16 자리 소수 | val f: Double = 3.1415926535 |
| Boolean | 1-bit | true, false | val g: Boolean = true |
| Char | 16-bit | 유니코드 문자 | val h: Char = 'A' |
val age: Int = 25 // 명시적 선언
val name = "Kotlin" // 타입 추론 적용 (String)
val pi = 3.14 // Double로 추론됨
- val을 사용하면 타입을 생략해도 컴파일러가 자동으로 결정 (Type Inference)
🔄 2. Kotlin의 타입 변환 (Type Conversion)
Kotlin은 암시적 변환(Implicit Conversion)을 지원하지 않음
즉, Int → Long 같은 자동 변환이 불가능하며, 명시적인 변환이 필요함
val a: Int = 10
val b: Long = a // ❌ 자동 변환 불가능 (Type mismatch)
val b: Long = a.toLong() // ✅ 명시적 변환 필요
| 변환 메서드 | 설명 |
| toByte() | Byte로 변환 |
| toShort() | Short로 변환 |
| toInt() | Int로 변환 |
| toLong() | Long으로 변환 |
| toFloat() | Float로 변환 |
| toDouble() | Double로 변환 |
val name = 10
val doubleNum = num.toDouble() // Int → Double 변환
🚀 3. 타입 추론(Type Inference)의 중요성
Kotlin에서는 변수 타입을 생략해도 자동으로 결정됩니다.
타입 추론이 중요한 이유는 코드를 간결하게 만들면서도, 타입 안정성을 유지할 수 있기 때문입니다.
✅ 1️⃣ 코드 가독성 증가
// 명시적 타입 선언 (불필요)
val name: String = "Kotlin"
val score: Int = 100
// 타입 추론 적용 (더 간결)
val name = "Kotlin" // String으로 추론
val score = 100 // Int로 추론
- 타입을 명시하지 않아도, 타입 안정성이 보장되면서 코드가 간결해짐
✅ 2️⃣ 불필요한 타입 변환 방지
fun add(a: Int, b: Int) = a + b // 반환 타입 생략 (Int로 추론)
- 반환 타입을 생략해도 컴파일러가 자동으로 Int로 결정
- 타입을 명시하는 경우보다 유연한 함수 작성 가능
✅ 3️⃣ 불필요한 타입 캐스팅 제거
Kotlin은 타입 추론을 활용하여 불필요한 캐스팅을 방지할 수 있습니다.
// 명시적 타입 캐스팅 필요 (Java 스타일)
val obj: Any = "Kotlin"
val str: String = obj as String // 명시적 캐스팅
// Kotlin의 스마트 캐스트 활용 (타입 추론)
if (obj is String) {
println(obj.length) // ✅ obj는 자동으로 String으로 처리됨
}
- is 연산자를 활용하면 별도의 캐스팅 없이 자동으로 타입이 추론됨
✅ 4️⃣ 컬렉션 타입 추론 활용
Kotlin에서는 컬렉션(List, Map 등)도 타입을 추론하여 처리합니다.
val numbers = listOf(1, 2, 3, 4, 5) // List<Int>로 추론
val mixed = listOf(1, "Kotlin", 3.14) // List<Any>로 추론
- numbers는 List<Int>로, mixed는 List<Any>로 자동 결정
❗️ 4. 타입 추론이 실패하는 경우
❌ 1️⃣ 모호한 타입이 있을 경우
val x // ❌ 오류: 타입을 추론할 수 없음
- 초기값 없이 변수를 선언하면 타입을 알 수 없기 때문에 오류 발생
fun sum(a: Int, b: Int) = a + b // ✅ Int 반환 타입 자동 추론
fun divide(a: Int, b: Int) = a / b.toDouble() // ✅ Double 반환으로 추론
- 하지만 복잡한 로직에서는 반환 타입을 명시하는 것이 더 안전함
🔥 var과 val의 타입 추론 차이
var num = 10 // Int로 추론됨
num = "Hello" // ❌ 오류: 타입 변경 불가
- var은 변경 가능한 변수지만, 초기 타입이 결정되면 다른 타입의 값을 할당할 수 없음
val message = "Hello" // String으로 추론됨
message = "Hi" // ❌ 오류: val은 재할당 불가
- val은 불변(immutable) 변수이므로, 한 번 값이 할당되면 변경할 수 없음
- 하지만 객체의 프로퍼티는 변경 가능
val user = mutableListOf(1, 2, 3) // List<Int>로 추론됨
user.add(4) // ✅ 가능 (리스트 내용은 변경 가능)
user = mutableListOf(5, 6) // ❌ 오류 (새로운 리스트로 재할당 불가)
- val은 참조(Reference)는 불변이지만, 내부 데이터는 변경 가능
🔥 기본 타입과 타입 추론 정리
| 개념 | 설명 |
| 기본 타입 | Int, Double, Boolean 등 객체로 존재하지만 최적화됨 |
| 타입 변환 | 자동 변환 없음, toInt(), toDouble() 등 명시적 변환 필요 |
| 타입 추론 | 변수 선언 시 타입 생략 가능 (val name = "Kotlin") |
| 스마트 캐스트 | is 연산자를 활용하여 명시적 캐스팅 없이 사용 가능 |
| 컬렉션 타입 추론 | listOf(1, 2, 3) → List<Int>로 자동 결정 |
타입을 명확하게 정의해야 하지만, 불필요한 타입 선언을 줄여 가독성을 높이는 것이 중요!
🤔 추가로 생각해 볼 질문들
- Kotlin에서는 타입이 항상 결정되는데, Java의 Object 타입과는 어떤 차이가 있을까?
- 자바에서는 int와 Integer가 존재하는데, Kotlin에서는 왜 Int만 있을까?
- 코틀린의 Unit 타입과 Java의 void는 어떤 차이가 있을까?
- 타입 추론을 무조건 사용하면 안 되는 경우는 언제일까?
- Kotlin에서 타입 추론을 활용한 제네릭(Generic) 함수는 어떻게 사용할까?