본문 바로가기
Kotlin

Kotlin에서 더블 콜론(::)은 무엇일까

by 서퍼리노 2023. 2. 7.
728x90

Kotlin을 사용하다 보면 종종 더블 콜론(::)을 사용하는 사례를 볼 수 있다.

이는 과연 무엇일까?

 

더블 콜론은 리플렉션(Reflection)을 위해 사용합니다.

Reflection이란?

Reflection is a set of language and library features that allows you to introspect the structure of your program at runtime.

공식 문서에서는 이런 식으로 소개하고 있습니다.

"리플렉션은 런타임 시 프로그램 구조를 검사할 수 있는 언어 및 라이브러리 기능 집합이다."라고 표현하고 있습니다.

 

코드를 작성하는 시점에 런타임 시점의 컴파일된 바이트 코드 중 원하는 함수의 위치를 알 수 없기 때문에 
런타임 시의 바이트 컴파일 된 바이트 코드를 이용하여 해당 함수의 값을 찾기 위해 사용합니다.

 

리플렉션은 런타임에 프로그램의 클래스를 조사하기 위해 사용되는 기술입니다.

코드를 작성하는 시점이 아닌 프로그램이 실행 중 일 때 인스턴스 등을 통해 객체의 내부 구조를 파악할 수 있습니다.

 

코틀린에서 더블콜론(::)을 명시하면, 변수나 클래스에 대한 참조를 할 수 있습니다.

더블콜론을 명시하면 변수가 아닌 객체로 접근할 수 있기 때문입니다.

 

리플렉션이 무슨 일을 하는지 조금 더 쉽게 알아보겠습니다.

 

클래스 참조

가장 기본적인 리플렉션의 기능은 Kotlin 클래스에 대한 런타임 참조를 가져오는 것입니다.

val c = MyClass.class

여기서 참조는 KClass 유형입니다.

 

함수 참조

리플렉션을 이용하면 함수를 참조할 수 있습니다.

fun isOdd(x: Int) = x % 2 != 0

해당 함수는 Int 형태의 x를 받아 그 수가 홀수인지 아닌지에 따라 참, 거짓을 반환합니다.

위와 같이 정의된 함수를 선언한 경우 직접 호출할 수 있습니다.

val numbers = listOf(1, 2, 3)
println(numbers.filter(::isOdd))
numbers라는 리스트의 값을 filter를 이용하여 함수를 사용한다면 위와 같이 사용할 수 있습니다.
inline fun IntArray.filter(
    predicate: (Int) -> Boolean
): List<Int>

해당 함수에 사용되는 filter의 내부 모습입니다.

 

predicate라는 (Int)를 입력받아, Boolean을 반환하기 때문에 함소를 참조하여 동일한 형식인 isOdd를 사용할 수 있습니다.

 

이러한 기능은

더블 콜론의 예상 유형이 콘텍스트에서 알려진 경우

오버로드된 함수와 함께도 사용할 수 있습니다.

이처럼 함수가 오버로드 되더라도 

Int일 경우엔 Int로

fun isOdd(x: Int) = x % 2 != 0
fun isOdd(s: String) = s == "brillig" || s == "slithy" || s == "tove"

val numbers = listOf(1, 2, 3)
println(numbers.filter(::isOdd)) // refers to isOdd(x: Int)

 

String일 경우엔 각각에 맞는 타입으로

fun isOdd(x: Int) = x % 2 != 0
fun isOdd(s: String) = s == "brillig" || s == "slithy" || s == "tove"

val strings = listOf("brillig", "asdf", "asdfa")
println(strings.filter(::isOdd)) // refers to isOdd(x: String)

값을 제대로 출력하는 모습을 볼 수 있다.

 

속성 참조

또한 속성을 참조할 수도 있습니다.

val x = 1

fun main() {
    println(::x.get())
    println(::x.name)
}

x의 속성을 참조하여, 

get()을 사용해 안에 들어 있는 값과,

name을 사용하여 해당 변수의 이름을 알 수 있었습니다. 

 

var y = 1

fun main() {
    ::y.set(2)
    println(y)
}

처음에는 1로 선언된 값이 참조와 set 함수를 이용하여 

변수를 var로 선언한다면 getter와 setter가 모두 생기기 때문에 값을 변경해 주는 것도 가능합니다.

 

 

val strs = listOf("a", "bc", "def")
println(strs.map(String::length))

map을 이용하여 String을 참조하면, 이런 식으로 문자열의 길이도 구할 수 있습니다.

728x90

'Kotlin' 카테고리의 다른 글

Kotlin - Infix 함수  (2) 2023.02.20
::class.java는 무엇일까  (0) 2023.02.07
[Kotlin] - map함수 (리스트 값 변경하기)  (0) 2023.02.02
[Kotlin] - filter사용하기  (0) 2023.01.30
[Kotlin] lateinit, by lazy  (0) 2023.01.27