will come true

[Kotlin] 변수, 초기화, lateinit, lazy, 데이터 타입, Any, Unit, Nothing 본문

Kotlin

[Kotlin] 변수, 초기화, lateinit, lazy, 데이터 타입, Any, Unit, Nothing

haehyun 2023. 5. 18. 02:15

변수

  • var (variable) : 초깃값이 할당된 후에도 값을 바꿀 수 있는 변수
  • val (value) : 초깃값이 할당되면 바꿀 수 없는 변수
    (val을 쓸 수 있는 상황에서는 되도록 val을 많이 사용하길 권장)
var 변수명:타입 = 값

변수명 뒤에 콜론(:)을 추가해 타입을 명시할 수 있는데, 대입하는 값에 따라 타입을(타입 추론)할 수 있을 때는 생략할 수 있다. 다만 메서드를 호출해서 반환값을 대입하는 경우에는 되도록 참조변수에 반환 타입을 지정해주는 게 좋다. 동료 개발자들이 이 변수가 무슨 타입인지 직관적으로 확인할 수 있으니까.

초기화

최상위에 선언한 변수나 클래스의 멤버 변수는 선언과 동시에 초깃값을 할당해야 한다.
함수 내부에 선언한 지역 변수는 선언과 동시에 초깃값을 할당하지 않아도 된다.

클래스내 멤버 변수로 빈 리스트 선언하기 ⭐

아래와 같이 클래스 내부에 아무것도 담지 않은 빈 리스트를 생성할 수 있는 이유도 animalList라는 참조변수의 초기값으로 ArrayList<Animal>타입 객체를 생성해서 그 주소를 초깃값으로 대입해줬기 때문에 가능한 것이다.

class Zoo {
	val animalList = ArrayList<Animal>()
}

여기서 "ArrayList에 Animal 객체가 계속 추가되면서 ArrayList 객체의 내용이 변경될텐데 var로 선언해야 하는 게 아닌가?" 싶을 수도 있으나 animalList 참조 변수에 저장되는 값은 생성된 ArrayList 타입 객체의 주소이다. 그리고 이렇게 한 번 선언된 객체의 주소는 코드가 끝날때까지 변하지 않는다. ← 이러한 조건 덕분에 val 로 선언할 수 있는 것이다. 실제로 이후 animalList에 Animal 객체를 추가하여도 ArrayList 객체의 내부 멤버 값(list 요소나 size 값 등)은 계속 변하지만, 객체의 주소는 변하지 않는다.

위와 같은 이유로 객체의 참조 변수는 val로 선언할 수 있다.

초기화 미루기

변수를 선언할 때 초깃값을 할당할 수 없는 경우. 예를 들면 특정 연산을 거친 후에야 알 수 있는(산출되는) 값을 최상단 혹은 클래스 멤버 변수 위치에 선언해야 할 때는 값을 이후에 할당할 것이라고 컴파일러에게 알려 주어야 한다.
*프로그래밍 코드의 오류를 잡아내는 건 컴파일러 담당. 기본 문법에 어긋나는 상황을 연출하고자 할 경우 컴파일러에게 별도로 언질을 줘야 빨간줄이 뜨지 않는다.

lateinit

특정 조건에 만족하는 변수에 lateinit 키워드를 붙여서 선언 이후에 초깃값을 할당하도록 만들 수 있다.
선언 시점에 아직 해당 변수에 대입할 값이 도출되지 않았을 때 사용한다.
*변수에 값이 할당되는 시점 : 최초로 변수에 대입연산자로 값을 할당할 때 (data = 10)

  • var 변수에만 사용 가능 (값을 바꿀 수 있음)
  • Int, Long, Short, Double, Float, Boolean, Byte 타입에는 사용 불가

val 변수는 setter()가 만들어지지 않기 때문에 선언할 때 초기화 해주지 않으면 값을 새로 저장하는 게 원칙적으로 불가능하다. 이 때문에 lateinit를 활용한 초기화 미루기를 적용할 수 없는 것.

// lateinit가 가능한 경우
lateinit var data1: String
lateinit var data2: TestClass
lateinit var arrayList:ArrayList<Int>
lateinit var array:Array<Int>

 

lazy

변수 선언문 뒤에 by lazy { } 형식으로 선언
소스에서 변수가 최초로 이용되는 순간 중괄호로 묶은 부분이 자동으로 실행되어 그 결괏값이 변수의 초깃값으로 할당된다. lateinit의 '나중에 값을 알게되면 저장할게'라는 취지와 달리, 어떠한 처리를 통해서 얻은 값을 저장하고자 할 경우 사용한다. (데이터에 별도 처리를 해줘야 하는 경우 혹은 특정 연산의 결과를 대입할 때)
*변수에 값이 할당되는 시점 : 최초로 변수가 이용될 때 (data, 대입 연산자 필요X)

class TestClass(){
   // 2. 호출되는 순간에 값 할당
    val a1: Int by lazy {
        println("lazy 변수 값 할당중")
        var temp = 1 + 2 + 3 + 4 + 5
        temp
    }
}

fun main(){
    val t1 = TestClass()
    // 1. 값이 없는 변수 호출
    println(t1.a1)			
}
lazy 변수 값 할당중
15

 

데이터 타입

기본 자료형(primitive type)의 단점

자바에서 int, double, float과 같은 기본 자료형이 멀쩡히 있음에도 Wrapper 클래스를 사용하던 이유를 떠올려보자.
객체가 아니기 때문에 null 값을 대입할 수 없고, 타입과 관련된 내부 멤버 및 메서드를 가질 수 없다는 점이 문제였다.
이 점을 개선하여 코틀린에서는 모든 기본자료형을 객체로 처리한다. int 기본 자료형 없이 Int 클래스만을 제공한다.

코틀린 데이터 타입

  • Int, Short, Long, Double, Float, Byte, Boolean
  • Char, String
    • 코틀린 Char은 Number 타입으로 표현할 수 없다.
    • """문자열""" : (Raw String) 키보드로 입력한 줄 바꿈이나 들여쓰기 등이 데이터에 그대로 반영된다.
    • .trimIndent() : 문자열 앞에 공백을 엎애 주는 메서드. Raw String 마지막에 사용된다.
  • Any
  • Unit
  • Nothing

 

Any

코틀린의 최상위 클래스. 모든 코틀린의 클래스는 Any의 하위 클래스이다.
Any 타입으로 선언한 변수에는 모든 타입의 데이터를 할당할 수 있다.
Any 에는 클래스가 갖춰야 할 기본적인 기능이 들어있다.

 

Unit

데이터 형식이 아닌 특수 목적 용도.
Unit 타입으로 선언한 변수는 Unit 객체만 대입할 수 있다.

이러한 특성을 활용해 함수의 반환문이 없음을 명시적으로 나타낼 때 Unit 타입을 사용한다.
함수의 반환값이 Unit라면 해당 함수를 호출하는 구문의 참조변수도 Unit 타입이어야 하는데, 해당 타입은 코드에서 사용되지 않기 때문에 Unit 타입을 받을 변수가 없다. 즉 아래와 같은 상황을 막기 위함.
함수 선언시 반환 타입을 생략하면 자동으로 Unit이 적용된다.

기껏 연산까지 해놓고 반환타입과 return문을 안적어서 Unit 타입이 반환되어버렸다. 메서드 호출부에서는 Int와 Unit 타입 미스매치잉 발생해 컴파일 에러가 표시된다.

 

아래 코드에서 a1 변수는 getData() 메서드 반환값 타입을 자동으로 판단해 Unit 타입으로 초기화된다.
아래처럼 코드를 작성해도 오류는 발생하지 않는다. 다만 아무 의미도 없는 코드일 뿐이다. 실제로 a1 변수의 값을 println() 해보면 kotlin.Unit 라는 타입명만 출력된다.

fun main(){
    val a1 = getData()
    println("$a1")
}

fun getData(): Unit {
    println("반환값이 없는 메서드 호출")
}
반환값이 없는 메서드 호출
kotlin.Unit

 

Nothing

null이나 예외를 반환하는 함수

 

 


개인 회고

봐도 봐도 자꾸 하나씩 깜빡한다.. 자바 문법이랑 머리에서 섞인 탓에 fun 으로 선언할 함수를 'public void~' 쓰고있음. 손에 완전히 붙을 때까지 코틀린 코드를 많이 써봐야겠다. 그리고 자바와 비슷하면서도 묘하게 다른 기능들도 있어서(결국 전부 자바 코드로 변환되긴 하지만) 자바 코드와 완전히 비교해서 이해하는 것도 별로 적절치 않을듯하다. 영어 공부할 때 한국어랑 억지로 1:1 비교해서 공부하면 오히려 이해가 어렵듯이, 아예 다른 새로운 언어를 공부한다는 마음가짐으로 새로 쌓아올려야겠다. 분명 코틀린 공부했었는데 왜 하나도 기억이 안나는지.. 역시 운동, 프로그래밍, 영어는 꾸준히 안하면 금새 허물어지는 것 같다.

Comments