Kotlin meetup let run apply lateinit

예제로 배우는 아름다운 코틀린의 기능들:Ready for Production

첫번째 코틀린 모임이 강남소재의 교육 스타트업인 Riiid 사무실에서 있었습니다. Riiid 는 데이터 기술을 통해 교육기회의 평준화를 목표로 하는 스타트업입니다. 이 모임 발표중 해재위님이 간단한 예제로 Kotlin 기능 소개를 해주신 세션영상을 정리하여 공개합니다

이 모임은 교육 스타트업인 Riiid(뤼이드)에서 안드로이드 개발자로 근무하고 계신 허재위 님 사회로 진행되었습니다. 아래 개요를 정리하였지만 동영상에서 데모와 함께 매우 쉽게 설명되어있으니 동영상을 보시는 것을 추천드립니다.


익스텐션

익스텐션은 기존의 객체에 원하는 동작을 추가로 삽입합니다.

public fun <T> List<T>.getOrNull(index: Int): T? {
  return if (index >= 0 && index <= lastIndex) get(index) else null
}

이런 개발 뉴스를 더 만나보세요

위의 코드는 기존 List<T>에 메서드 getOrNull을 넣은 것이고요. 범위가 맞지 않으면 null을 반환하는 것입니다. 기존의 코드에 여러가지 내용을 추가하면 전체적인 프로그래밍에 효율적으로 사용할 수 있습니다.

join을 구분자(separator)에 인자를 붙여 쓰고 싶을 때에는 아래와 같이 사용할 수 있습니다.

fun String.join(vararg strings: String): String =
  strings.joinToString(separator = this)

데이터 클래스

data class의 생성자에 기술된 모델 정보를 가지고 equalhashCode 등의 메서드를 자동으로 생성해주기 때문에 유용합니다. 이런 특징은 Rx를 사용할 때 더 빛이 납니다.

유틸리티

let

let은 값이 있는 경우에 다른 코드 블록을 추가로 수행하는 것입니다.

override fun onBindViewHolder(holder: RepoViewHolder?, position: int) {
  repos.getOrNull(position)?.let {
    holder?.setRepo(it)
  }
}

만약에 getOrNull의 반환값을 받아 비교하고 참인 경우에 그 변수를 쓴다고 생각하면 코드가 좀 더 번잡해집니다. 파라미터가 없으면 it으로 전달되기 때문에 간단히 결과값을 사용할 수 있습니다.

apply

생성자를 확장할 방법은 마땅치 않습니다. 초기화 과정이 필요할 때 apply를 사용해봅시다.

private fun initHttpLoggingIntercepter(): HttpLoggingIntercepter {
  return HttpLoggingIntercepter().apply {
    level = if (BuildConfig.DEBUG) {
      HttpLoggingIntercepter.Level.BODY
    } else {
      HttpLoggingInterceptor.Level.NONE
    }
  }
}

levelHttpLoggingIntercepter 인스턴스의 level 멤버변수입니다. 멤버변수의 초기화나 초기에 호출할 메서들들을 한번에 모아 일목요연하게 다룰 수 있습니다.

run

어떤 경우에는 어떤 인스턴스에 관련된 필드나 메서드에 연속적으로 접근해야할 때가 있습니다. 이런 경우 run을 쓸 수 있습니다.

class RepoViewHolder(private val view: View): RecyclerView.ViewHolder(view) {
  fun setRepo(repo: Repository) {
    view.run {
      findViewById(R.id.fg).setOnClickListener {
        val message = repo.run {
          "\n".join(fullName, language)
        }
        Toast.makeText(view.context, message, Toast.LENGTH_SHORT).show()
      }
      ...
    }
  }
}

view.run 키워드 이후에 view 내의 필드나 메서드에 대한 접근이 암묵적으로 허용이 됩니다. view.findViewById(R.id.fg) 대신에 findViewById(R.id.fg)를 쓸 수 있습니다. 마찬가지로 repo.run 이후로 repo에 속한 repo.fullNamerepo.language를 자연스럽게 쓸 수 있습니다.

lazy

처음에 null을 넣고 나중에 초기화를 시켰던 경우도 있습니다. 초기화 포인트를 여러 곳에 분리시켜서 불편하셨다면 lazy 키워드를 이용할 수 있습니다.

private val adapter by lazy { RepoAdapter(this) }

위의 코드는 adapter가 실제로 사용이 되어야 할 때 뒤 늦게 RepoAdapter(this)를 대입합니다.

lateinit

?. 엘비스 연산자를 통해 널인 경우와 아닌 경우를 구분하는 것은 null 반환값이 있는 경우엔 유용하지만 그 값이 null일 가능성이 없는 경우에도 굳이 써야 할까라는 의문이 들 수 있습니다. 만약에 뒤늦게 값이 대입되어서 절대 null 값을 참조할 가능성이 없다면 변수에 lateinit를 붙여 나중에라도 null이 아닐 것임을 알릴 수 있습니다.

Resources

컨텐츠에 대하여

이 컨텐츠는 저자의 허가 하에 이곳에서 공유합니다.

Realm Team

Realm의 미션은 더 나은 앱을 빠르게 개발할 수 있도록 돕는 것입니다. 이를 위해 저희는 개발자들이 실시간 협업, 가상 현실, 라이브 데이터 동기화, 오프라인 경험, 메시징 등 정교하고 강력한 기능을 쉽게 개발할 수 있도록 하는 개발 도구와 플랫폼을 제공하고 있습니다.

저희는 모바일 인터넷이 수많은 사용자와 보다 많은 디바이스가 속한 개방형 네트워크와 이들 간의 실시간 상호 작용으로 진화할 것이라고 믿으며, 개발자가 이같은 방향으로 발전할 수 있도록 돕기 위해 저희 제품들을 개발하고 있습니다.

4 design patterns for a RESTless mobile integration »

close