---
description: 변수 & 타입 시스템
---

# 1. Variable & Type System

코틀린은 “기본 불변(immutable), 명시적 null, 명시적 숫자 변환, 객체처럼 보이지만 런타임은 원시 타입 최적화”가 핵심입니다. 실무에서는 `val` 우선, nullable은 `?`로 드러내고, 컬렉션은 외부엔 불변으로 공개하세요.



### 1) `var` vs `val` — 코틀린의 기본 철학

* `val` : 재할당 불가(읽기 전용). **기본값**으로 사용 권장
* `var` : 재할당 가능(가변)

```kotlin
val port = 8080     // 불변
var retries = 3     // 가변
retries += 1
```

#### 자바와 무엇이 다른가?

* Java: 기본 가변, 필요하면 `final`
* Kotlin: **가변/불변을 선언 시 강제** → 실수 줄고, 병행성에 유리

#### 실무 팁

* 먼저 \*\*전부 `val`\*\*로 시작 → “정말 필요할 때만” `var`.
* `val` 컬렉션은 “참조만” 불변입니다. 내용까지 불변으로 노출하려면 불변 인터페이스(`List`, `Set`)를 공개하세요.

***

### 2) 타입 표기 & 타입 추론

* 표기 순서: **이름: 타입**
* 초기값이 있으면 대부분 **타입 생략** 가능

```kotlin
val name: String = "Kotlin"
val count = 10           // Int로 추론
```

* 초기화 미루면 **타입 필요**

```kotlin
var title: String
title = "Hello"
```

***

### 3) 원시 타입은 “객체처럼 보이되, 원시로 컴파일”

* 코드에선 `Int`, `Long`, `Boolean` 등 **클래스처럼 보임**
* **컴파일러가 가능하면 JVM primitive**로 최적화 (성능은 Java와 동일)
* 제네릭/nullable 등 불가피한 경우에만 박싱됨

#### 숫자 변환은 명시적

자바의 암시적 확대 변환(예: `int -> long`) 없음. **항상 `toXxx()`** 사용.

```kotlin
val i: Int = 1
val l: Long = i.toLong()   // 반드시 변환 호출
```

***

### 4) Null-safety: 타입으로 null을 “보이게” 만들기

* 기본은 **non-null**: `String`
* null 허용은 **`?`**: `String?`

```kotlin
val a: String = "ok"
// a = null  // 컴파일 에러

val b: String? = null
println(b?.length ?: 0)   // safe-call + elvis
```

#### 핵심 도구

* **Safe call** `?.` : null이면 호출/접근 스킵 → 결과 null
* **Elvis** `?:` : null일 때 기본값
* **Non-null 단언** `!!` : “진짜 null 아님”을 보장할 때만 (실수 시 NPE)

#### 자바와 섞일 때(플랫폼 타입)

* 자바에서 넘어온 값은 null 정보가 불명확할 수 있음 → **직접 null 방어** 또는 자바에 `@Nullable/@NotNull` 붙이기

***

### 5) 실무 패턴 모음

#### A. Android ViewModel: 백킹 프로퍼티로 “읽기 전용” 공개

```kotlin
class CounterViewModel : ViewModel() {
    private val _count = MutableLiveData(0) // 내부에서만 변경
    val count: LiveData<Int> get() = _count // 외부엔 읽기 전용

    fun inc() { _count.value = (_count.value ?: 0) + 1 }
}
```

* 공개는 **불변 타입**(LiveData), 내부만 가변(MutableLiveData)

#### B. 서버 DTO: null/기본값으로 NPE 차단

```kotlin
data class UserDto(
    val id: Long,
    val name: String,
    val nickname: String?,                 // 없으면 null
    val tags: List<String> = emptyList()   // 기본값으로 빈 리스트
)
```

* “옵션 필드”는 `?`로, “컬렉션”은 **기본값**으로 방어

#### C. DI (Hilt/Dagger/Koin): 생성자 주입 + 불변 프로퍼티

```kotlin
class Repo @Inject constructor(
    private val api: ApiService,    // val로 저장(재할당 불가)
    private val cache: Cache
)
```

* 보일러플레이트 감소 + null/재할당 위험 차단
* 필드 주입이 필요하면 `lateinit var` (초기화 전 접근 금지 주의)

#### D. 불변 상태 모델링 (Compose/StateFlow)

```kotlin
data class UiState(val user: User?, val loading: Boolean = false)

class VM : ViewModel() {
    private val _ui = MutableStateFlow(UiState(null, true))
    val ui: StateFlow<UiState> = _ui

    fun loaded(u: User) { _ui.value = UiState(u, false) } // 새 객체로 교체
}
```

* **불변 데이터 클래스 + copy/new**로 상태 관리 → 버그/레이스 감소

***

### 6) 흔한 실수 & 방어법

* ❌ 숫자 암시적 변환 가정\
  → ✅ `toLong()`, `toDouble()` 등 **항상 명시적 변환**
* ❌ `!!` 남발\
  → ✅ `?.`, `?:`, `let`, 조기 `return`으로 재구성
* ❌ `var`로 모두 선언\
  → ✅ 기본은 `val`, 컬렉션은 외부에 불변 인터페이스로 공개
* ❌ DTO/상태 모델에 가변 프로퍼티\
  → ✅ **`data class + val`** 조합, 변경은 `copy()`로
* ❌ 자바 혼용 시 null 가정\
  → ✅ 자바에 어노테이션 부여 또는 코틀린 쪽에서 방어적 처리
