Kotlin/Basic

Kotlin - 변수와 타입 (Variable and Data Type)

에포트 2021. 5. 21. 15:05

내가 코틀린을 배우면서 코틀린에 있어 특별하다고 생각되는 부분들 또는 메모해두어야 할 점들을 여기에 적어놓으려고 한다.

 

변수선언

var

먼저, 변수를 선언하는 방식에는 두 가지 방식이 있는데, 첫번째는 var를 사용하는 방식이다. 이 방식을 사용하면 언제든 읽고 쓰고 수정할 수 있는 변수 (variable) 가 생성된다. 이 경우 변수에 객체가 담기더라도 언제든 수정할 수 있다.

 

예시

fun main() {
    var a: Int = 10;
    println(a);
    a = 20;
    println(a);
}

 

출력

10
20

 

val

두번째는 val를 사용하는 방식이다. 이 방식을 사용하면 선언시에만 초기화가 가능한 변수 (value) 가 생성된다. 이 방식을 통해서 초기화된 변수는 그 값을 후에 변경할 수가 없다. 따라서 값이 바뀌면 안되는 변수들을 선언할 때 유용하게 사용될 수 있다. 이 경우 한번 객체가 변수에 담기고 나면 수정할 수 없다.

 

그러나 val로 객체를 설정하더라도, 객체의 참조만 바꿀 수 없을 뿐이지, 객체 내부에서 어떤 동작이 일어나는 것은 바꿀 수 없다. 예를 들어 val을 이용하여 선언한 변수도 객체의 속성 또는 함수 등을 바꿀 수 있다.

 

예시

fun main() {
    val a: Int;
    a = 10;
    println(a);
}

 

출력

10

 

val을 통하여 변수를 선언한 후, 값을 바꿔주려는 시도를 하면 Val cannot be reassigned 에러가 뜬다.

 

const

const는 변수가 아닌 상수를 지정할 때 쓰는 키워드이다. 상수는 컴파일 시점에 그 값이 결정되어 절대 바꿀 수 없는 값이 된다. const는 val 앞에 붙여 사용하게 되는데, 상수로 선언될 수 있는 값은 기본 자료형만 가능하며, 런타임에 생성될 수 있는 일반적인 다른 클래스의 객체들은 담을 수 없다. 또한, 상수는 클래스 또는 함수에서 선언이 불가하며, 상수는 오로지 companion object 안에 선언하여 객체의 생성과 관계 없이 클래스와 관계된 고정적인 값으로만 사용할 수 있다.

 

상수의 이름은 의례적으로 대문자와 언더바만 사용하는데, 이로써 후에 사용할 때에 상수라는 점을 알릴 수 있다.

 

변수는 런타임 시 객체를 생성하여 담기 때문에 컴파일 때 미리 값이 결정되는 상수를 사용하는 것 보다 성능이 저하될 수 있다. 따라서 값이 바뀌지 않는, 상수가 필요한 경우에 있어서는 성능 향상을 위해 상수를 사용하는 것이 바람직하다.

 

lateinit

코틀린에서는 변수에 객체를 바로 할당하지 않는다면 컴파일이 기본적으로 이루어지지 않는데, 경우에 따라서 변수에 객체를 할당하는 것을 미루어야할 때가 있다 (선언과 동시에 할 수 없을 때도 있다). 이 경우 var 앞에 lateinit을 사용하여 변수를 선언만 해놓고 객체의 할당은 나중에 할 수 있는 키워드이다.

 

lateinit var 변수에는 제한사항이 몇 가지 있다.

1. 초기값을 할당하기 전 까지는 변수를 사용할 수 없다. (위반 시 에러 발생)

2. 기본 자료형에는 사용할 수 없다. (그러나 String에는 사용 가능)

 

lateinit 변수의 초기화가 이루어졌는지 확인할 때에는 isInitialized 함수를 쓰는데, 초기화가 되지 않았다면 변수를 사용할 수 없기 때문에 앞에 콜론 두개 (::) 를 붙여주어야 한다.

 

예시

 

fun main() {
    var a = LateInitSample()
    
    println(a.getLateInitText())
    a.text = "sorry for being late"
    println(a.getLateInitText())
}

class LateInitSample {
    lateinit var text: String
    
    fun getLateInitText(): String {
        if(::text.isInitialized) {
            return text
        } else {
            return "NOT INITIALIZED YET"
        }
    }
}

 

출력

 

NOT INITIALIZED YET
sorry for being late

 

lazy

변수가 선언되더라도 변수가 사용되는 시점까지 초기화를 자동으로 늦춰주는 lazy delegate properties (지연 대리자 속성) 이다. lazy라는 키워드를 by 뒤에 람다함수와 함께 사용하여 선언한다. 실제 선언되는 시간을 늦춰 코드를 조금 더 최적화할 수 있다.

 

예시

 

fun main() {
    val a: Int by lazy{ 7 }
    
    println(a)
}

 

출력

 

7

 

Null safety

변수에 있어서 기본적으로는 자료형을 선언한 후에 값을 지정해주어야 한다. 그러나, 초기화되지 않으면 고전적인 언어들은 변수가 선언된 후에 기본값으로 초기화되거나, 또는 값이 할당되지 않았다는 표시로 null 값을 가지게 된다. 그러나, 코틀린은 기본 변수에서 null 값을 허용하지 않으며, 변수에 값을 할당하지 않은채로 변수를 사용한다면 에러가 뜨게 된다. 따라서 변수를 참조하여 사용하기 전까지 무조건 변수에는 값이 할당되어야 프로그램이 구동이 된다. 예를 들어, 아래 코드는 Variable 'a' must be initialized 에러를 일으킨다.

 

에러 예시

fun main() {
    val a: Int;
    println(a);
}

 

그러나 프로그램에 따라서 변수에 값이 할당되지 않았다는 것을 하나의 정보로 사용하는 경우도 있다. 따라서 이런 경우에 null이 변수에 할당이 가능하다는 것을 지정해줄 수 있는데, 이 경우 변수 선언 시에, 자료형 뒤에 물음표 (?) 를 붙이면 null을 허용하는, nullable 변수로 선언할 수 있다.

 

예시

fun main() {
    val a: Int? = null;
    println(a);
}

 

출력

null

 

nullable 변수는 null인 상태로 연산할 시, null pointer exception이 발생할 수 있으므로, 꼭 필요한 경우에 한해 주의하여 사용해야 한다.

 

배열

코틀린에서 배열을 만들어보자. 먼저 기본적인 배열은 arrayOf 메서드를 사용하여 만들 수 있다.

 

예시

fun main() {
    val arr = arrayOf(1, 2, 3, 4, 5);
    println(arr[2]);
}

 

출력

3

 

변수들을 집어넣기 전에 비어있는 배열 (null로 채워진 배열) 을 만들고 싶다면 arrayOfNulls 메서드를 사용하면 된다.

 

예시

fun main() {
    val nullArr = arrayOfNulls<Int>(5);
    nullArr[2] = 1;
    println(nullArr[1]);
    println(nullArr[2]);
}

 

출력

null
1

 

배열은 처음 선언했을 때의 전체크기를 변경할 수 없다는 단점이 있지만, 한 번 선언을 해두면 다른 자료구조보다 빠른 입출력이 가능하다는 장점이 있다.

 

리스트

리스트는 Collection이라는 클래스를 상속받는 서브클래스 중 가장 단순한 형태의 클래스이다. 여러 개의 데이터를 원하는 순서로 넣어 관리하는 형태의 자료형이다. 리스트에는 두 가지 형태가 있는데, 하나는 그냥 List 이고, 하나는 MutableList이다. MutableList는 말 그대로 변할 수 있는 (mutable) 리스트이며, List는 변할 수 없는 리스트, 즉 생성시에 넣은 객체를 대체, 추가, 삭제할 수 없다. 마치 파이썬의 튜플과 같은 역할을 한다고 볼 수 있다. 상황에 맞춰 이를 선택하면 된다.

 

리스트를 만들 때는 listOf 함수 또는 mutableListOf 함수를 사용하면 되는데, 각각 당연히 List와 MutableList를 만들어주는 함수이며, 안에 들어갈 객체들을 콤마로 구분하여 넣어주면 된다. MutableList는 요소의 추가 (add) 와 삭제 (remove, removeAt) 외에도, 무작위 섞기 (shuffle) 과 정렬 (sort) 기능을 지원한다. 특정 위치의 요소를 다른 요소로 대체 (list[i] = something) 도 가능하다.

 

타입추론

타입추론은 변수에 자료형을 명시해주지 않더라도 코틀린에서 자동적으로 타입을 추론하는 기능이다. 이는 변수가 선언될 때 할당되는 값의 형태를 통해 자료형을 추론할 수 있기 때문이다. 그렇다면 자료형 없이 값을 할당한다면 어떤 자료형들이 기본적으로 할당이 될까?

 

정수

정수는 기본적으로 Int형 변수로 지정된다. 아래 예시는 Int로 할당이 되었다.

 

val a = 123;

 

정수 뒤에 L이 붙으면 Long형 변수로 지정된다. 아래 예시는 Long으로 할당이 되었다.

 

val a = 123L;

 

실수

일반 실수형 리터럴은 Double형 변수로 지정된다. 아래 예시는 Double로 할당이 되었다.

 

val a = 12.5;

 

f가 붙은 실수형 리터럴은 Float로 추론된다. 아래 예시는 Float로 할당이 되었다.

 

val a = 12.5f;

 

문자와 문자열

문자를 다루는 자료형에는 char과 string이 있다. char은 문자 하나를 담을 수 있는 자료형이며, string은 문자열을 담을 수 있는 자료형이다. 두 자료형은 서로 선언 방식이 다른데, char은 작은 따옴표 (') 를 통해서 선언하며 string은 큰 따옴표 (") 를 통해서 선언한다. 작은 따옴표를 사용하여 선언하면 char로 추론이 되며, 큰 따옴표를 사용하여 선언하면 string으로 추론이 된다.

 

출처

https://www.youtube.com/playlist?list=PLQdnHjXZyYadiw5aV3p6DwUdXV2bZuhlN