Develop!/Kotlin

멤버참조 in Kotlin

체리필터 2023. 9. 27. 15:47
728x90
반응형

함수, 프로퍼티, 생성자에 대해서 호출하는 뻔한 람다를 대신할 수 있다. 사용법은 클래스 이름과 콜론 2개를 연결시켜 사용하면 된다. 관련된 내용은 아래 예제를 통해 확인해 볼 수 있다.

data class Message(
    val sender: String,
    val text: String,
    val isRead: Boolean
)

fun propertyReferenece() {
    val messages = listOf(
        Message("Kitty", "Hey!", true),
        Message("Kitty", "Where are you?", false)
    )

    val unread1 = messages.filterNot(Message::isRead)
    val unread2 = messages.filterNot { it.isRead }

    println(unread1.size)
    println(unread2.size)
    println(unread1.single().text)
    println(unread2.single().text)
}

Message라는 data class를 만들고 message list 중에서 읽지 않은 것만 필터해서 가지고 오는 로직이다. 이 때 보통 사용할 수 있는 it.isRead 대신에 "클래스이름::함수이름"과 같은 방법으로 사용할 수 있다. 아래 처럼 실행 결과는 동일함을 알 수 있다.

정렬 순서를 지정할 때에도 유용하게 사용할 수 있다.

fun sortWith() {
    val messages = listOf(
        Message("Kitty", "Hey!", true),
        Message("Kitty", "Where are you?", false),
        Message("Boss", "Meeting today", false)
    )

    val sortedMessages = messages.sortedWith(compareBy(
        Message::isRead, Message::sender
    ))
    println(sortedMessages)
}

compareBy에 isRead와 sender를 멤버 참조 형식으로 전달하였다. compareBy에 인자를 하나만 넘기고 sortedWith에 전달하면 sortedBy와 같은 결과를 얻을 수 있다.

함수도 참조로 넘길 수 있다. 메시지가 중요한지의 여부를 결정하는 함수를 별도로 만들어 두고 이를 넘겨서 메시지 리스트를 검사할 수 있다.

data class Message(
    val sender: String,
    val text: String,
    val isRead: Boolean,
    val attachments: List<Attachment>
)

data class Attachment(
    val type: String,
    val name: String
)

fun Message.isImportant(): Boolean =
    text.contains("Salary increase") ||
            attachments.any {
                it.type == "image" &&
                        it.name.contains("cat")
            }

fun functionReference() {
    val messages = listOf(
        Message("Boss", "Let's discuss goals for next year", false, listOf(Attachment("image", "cute cats")))
    )
    val result = messages.any(Message::isImportant)
    println(result)
}

Message class에 isImportant 라는 함수를 확장한다.

해당 함수는 내용에 "Salary increase"라는 문구가 들어가 있거나, 첨부 파일이 이미지 파일이면서 파일명에 "cat"이 들어가 있는 경우이다.

정의 된 isImportant 함수를 any 안에 "Message::isImportant" 처럼 작성해서 함수 참조로 넘길 수 있다. 결과는 아래와 같다.

어떤 클래스에 소속된 함수가 아니라 최상위 함수라면 "클래스명::함수명" 처럼 사용하지 않고 그냥 "::함수명"처럼 사용할 수 있다.

생성자도 참조할 수 있다. 다음의 코드를 보면 바로 알 수 있다.

data class Student(
    val id: Int,
    val name: String
)

fun constructorReference() {
    val names = listOf("Alice", "Bob")

    val students1 = names.mapIndexed { index, name -> Student(index, name) }
    println(students1)

    val students2 = names.mapIndexed(::Student)
    println(students2)
}

람다처럼 사용할 수 있고, Student가 최상위에 있으므로 "::Student" 처럼 생성자를 참조로 넘길 수도 있다. 실행 결과는 아래와 같다.

 

728x90
반응형

'Develop! > Kotlin' 카테고리의 다른 글

고차함수, 리스트 조작 in Kotlin  (0) 2023.10.04
컬렉션에 대한 연산 in Kotlin  (0) 2023.09.25
람다 in Kotlin  (0) 2023.09.25
제네릭스 in Kotlin  (0) 2023.09.22
안전한 호출과 엘비스 연산자 in kotlin  (0) 2023.09.14