티스토리 뷰

반응형

가변성과 읽기 전용 프로퍼티

코틀린을 처음 공부하다보니 가변성, 읽기 전용 프로퍼티라는 키워드를 많이 보게되는데 계속 보다보니 점점 더 헷갈려서 한번 정리를 해보려고 합니다.

 

이번 글에서 정리할 내용은 크게 3가지입니다.

1. 읽기 전용 프로퍼티(val) vs 가변 프로퍼티(var)

2. 읽기 전용 컬렉션(List) vs 가변 컬렉션(MutableList)

3. 1번 2번을 같이 사용할 때

 

읽기 전용 프로퍼티(val) vs 가변 프로퍼티(var)

코틀린을 조금이라도 사용해보았다면 val, var을 사용해 보았을 거다.

 

val, var의 간단한 특징은 아래와 같다.

val: 읽기 전용 프로퍼티, 값을 할당하면 변경이 불가능하다, 값(Value)의 약자
var: 가변 프로퍼티, 값을 할당한 후에도 변경이 가능하다. 변수(Variable)의 약자

 

두개의 차이를 좀 더 쉽게 이해할 수 있게 간단한 코드를 보자.

val a: Int = 1  // 읽기 전용 프로퍼티
a = 2  // [Error] a는 값 변경이 불가능함

var b: Int = 1  // 가변 프로퍼티
b = 2  // [OK] b는 값 변경이 가능함

val는 한번 값을 설정하고 나면 변경이 불가능하고 var은 값 변경이 가능하다.

 

 

읽기 전용 컬렉션(List) vs 가변 컬렉션(MutableList)

추가로 코틀린은 val, var과 같이 컬렉션 타입에도 읽기 전용(Immutable)과 변경 가능(Mutable) 두가지로 나뉘어져 있다.

 

변경 가능(Mutable)의 경우를 먼저 살펴보자.

val list = mutableListOf(1,2,3)  // 가변 컬렉션
list.add(4) // 리스트 수정이 가능하다

MutableList의 경우 add 함수를 통해 리스트에 값을 추가가 가능하다. 

우리가 일반적으로 생각하는 자바의 리스트와 같다.

 

어라?? 근데 잘 살펴보면 list라는 변수를 val인 읽기 전용프로퍼티로 선언했는데 왜 수정이 가능할까??

이 부분은 좀 더 아래쪽에서 자세히 살펴보자.

 

그럼 읽기 전용(Immutable)의 경우를 살펴보자.

val list = listOf(1,2,3)  // 읽기 전용 컬렉션
list.add(4) // [Error] 리스트 수정이 불가능하다.

읽기 전용이라는 말 그대로 리스트 수정을 할려고 하면 컴파일에러가 발생한다.

 

코틀린 언어의 경우 변경이 필요한 경우와 필요하지 않은 경우를 구분하여

만약 변경이 필요하지 않은 경우이면 이를 코드상에서 제한 할 수 있게 하여 의도치 않은 변경을 막을려고 노력한거 같다.

 

 

가변성과 읽기 전용 프로퍼티

프로퍼티와 컬렉션에 대해 살펴보았는데 위의 val list = mutableListOf() 부분을 다시 한번 살펴보자.

 

여기에서의 중요 포인트는 프로퍼티와 컬렉션을 따로따로 생각해야 한다는 것이다.

val list = mutableListOf(1,2,3) // list는 읽기전용
list.add(4) // 가변성

println(list) // [1,2,3,4]

 

  • 프로퍼티 기준: list는 val이기 때문에 읽기전용 속성이다.
  • 컬렉션 기준: list는 mutableList이기 때문에 가변 컬렉션이다.

가변 컬렉션이기 때문에 컬렉션 자체는 가변성이 있어 add 함수가 사용이 가능한것이다.

 

다른 예시를 통해 좀 더 자세히 살펴보자.

두가지 변경 가능 리스트

val list1: MutableList<Int> = mutableListOf(5)
var list2: List<Int> = listOf(5)

list1.add(1)
list2 = list2 + 1

두개의 리스트 list1, list2가 존재한다. 둘 다 변경 가능하지만 이 둘은 큰 차이가 있다.

 

먼저 list1을 보자.

list1의 경우 val 읽기전용 프로퍼티로 선언하였지만 타입이 가변 컬렉션이기 때문에 컬렉션 값 변경이 가능하다.

 

add() 메서드 실행

가변 컬렉션이기 때문에 list1.add()를 통해서 컬렉션 내의 값이 추가가 된다.

그러나 값이 추가되어도 list1프로퍼티 기준에서는 바라보는곳의 차이가 없다.

 

혹시 그림만 보고 그럼 5라는 값이 변경되면 list1프로퍼티도 변경되었다고 인식하는건가?? 라는 생각이 있을수 있다.

그림은 최대한 간단하게 표현을 한거라 실제로 list1프로퍼티는 값이 아닌 리스트의 주소를 바라보고 있기 때문에 5라는 값의 변경에는 영향을 받지 않는다.

 

 

다음은 list2이다.

list2의 경우 타입이 읽기 전용 컬렉션이지만 var 가변 프로퍼티로 선언하였기때문에 프로퍼티 값 변경이 가능하다.

다만 가변 프로퍼티이기 때문에 컬렉션내의 값 변경이 아닌 list2 프로퍼티 전체의 변경만 가능하다.

그림을 보면 6이라는 값을 가진 다른 리스트를 바라보도록 변경이 되는걸 확인할 수 있다.

 

그러면 list1 vs list2 어떤걸 사용해야 할까??

너무 진부한 얘기 일 수 있지만 상황에 맞게 사용하는것이 좋다. 

컬렉션의 변경이 필요한 경우에는 list1, 프로퍼티의 변경이 필요한 경우에는 list2를 사용한다.

 

가장 이상적인것은 의도치 않게 변경되는것을 프로퍼티, 컬렉션 둘다 읽기전용으로 사용하는 것이다.

val list: List<Int> = listOf(5)

하지만 이는 이상적인 형태일뿐 코드를 작성하다보면 list1 or list2 와 같이 변경을 허용해줘야 하는 경우도 반드시 필요하게 되기 때문에

가능한 범위내에서 최대한 변경이 일어나지 않는 방식을 사용하는것이 좋을거 같다.

 

만약에 변경지점을 최대한 없애고 싶다면 (1)Mutable(변경 가능)한 형태로 선언을 한뒤 (2)필요한 변경을 진행하고 (3)변경이 끝난 시점에 Immutablse(변경 불가능)한 형태로 변경을 해주는 방법도 있다.

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함