Page tree
Skip to end of metadata
Go to start of metadata

개발 환경

Kotlin

  • 자바 플랫폼에서 돌아가는 프로그래밍 언어
  • 간결하고 실용적이며, 자바 코드와의 상호운용성을 중시한다.

Kotlin 체험하기

Hello, World!

fun main() {
    println("Hello, world!!!")
}
  • Package specification is optional
  • In Kotlin 1.3, you can declare mainwithout any parameters.
  • semicolons are optional

코틀린은 간결한 구문을 어떻게 지원하는가?

  • 확장 함수
  • 중위 호출
  • 연산자 오버로딩
  • get 메서드에 대한 관례
  • 람다를 괄호 밖으로 빼내는 관례
  • 수신 객체 지정 람다

확장 함수

fun main() {
    print(lastChar("Kotlin"))
}

fun lastChar(s: String): Char {
    return s.get(s.length - 1)
}
fun main() {
    print("Kotlin".lastChar())
}

fun String.lastChar(): Char {
    return this.get(this.length - 1)
}

중위 표기

1.to("one")
infix fun Any.to(other: Any) = Pair(this, other)
1 to "one"

연산자 오버로딩

fun main() {
    print(Point(0, 1).plus(Point(1, 2)))
}

data class Point(val x: Int, val y: Int) {
    fun plus(other: Point): Point {
        return Point(x + other.x, y + other.y)
    }
}
fun main() {
    print(Point(0, 1) + Point(1, 2))
}

data class Point(val x: Int, val y: Int)

operator fun Point.plus(other: Point): Point {
    return Point(x + other.x, y + other.y)
}

get 메서드에 대한 관례

val names = listOf("Jason", "Pobi")
names.get(0)
names[0]

람다를 괄호 밖으로 빼내는 관례

check(false, { -> "Check failed." })
check(false) { "Check failed." }

수신 객체 지정 람다

val sb = StringBuilder()
sb.append("Yes")
sb.append("No")
sb.apply {
    this.append("Yes")
    append("No")
}

Scope Functions

자동차 경주 게임

기능 요구 사항

  • 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출 수 있다.
  • 각 자동차에 이름을 부여할 수 있다. 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다.
  • 자동차 이름은 쉼표(,)를 기준으로 구분하며 이름은 5자 이하만 가능하다.
  • 사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다.
  • 전진하는 조건은 0에서 9 사이에서 random 값을 구한 후 random 값이 4 이상일 경우 전진하고, 3 이하의 값이면 멈춘다.
  • 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다.

실행 결과

  • 위 요구사항에 따라 3대의 자동차가 5번 움직였을 경우 프로그램을 실행한 결과는 다음과 같다.

    경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분).
    pobi,crong,honux
    시도할 회수는 몇회인가요?
    5
    
    실행 결과
    pobi : -
    crong : -
    honux : -
    
    pobi : --
    crong : -
    honux : --
    
    pobi : ---
    crong : --
    honux : ---
    
    pobi : ----
    crong : ---
    honux : ----
    
    pobi : -----
    crong : ----
    honux : -----
    
    pobi : -----
    crong : ----
    honux : -----
    
    pobi, honux가 최종 우승했습니다.

코드 리뷰

  1. kotlin.random.Random
    • Kotlin 1.3 이후 추가
    • Kotlin의 멀티 플랫폼(JVM, JS 등)을 모두 지원하기 위해 등장
    • 동반 객체(companion object) 제공 (companion object Default : Random())
    • import kotlin.random.Random
      import kotlin.random.nextInt
      
      fun main() {
          Random.nextInt(0, 10)
          Random.nextInt(0..9)
      }
    • @SinceKotlin("1.3")
      public fun Random.nextInt(range: IntRange): Int = when {
          range.isEmpty() -> throw IllegalArgumentException("Cannot get random in empty range: $range")
          range.last < Int.MAX_VALUE -> nextInt(range.first, range.last + 1)
          range.first > Int.MIN_VALUE -> nextInt(range.first - 1, range.last) + 1
          else -> nextInt()
      }
  2. onEach
    • 지정된 작업을 수행하고 컬렉션을 반환 (forEach는 반환이 없다.)
    • inline fun <T, C : Iterable<T>> C.onEach(
          action: (T) -> Unit
      ): C
      
      inline fun <K, V, M : Map<out K, V>> M.onEach(
          action: (Entry<K, V>) -> Unit
      ): M
  3. lateinit var
    • null이 될 수 없는 프로퍼티에 지정하면 프로퍼티를 생성자가 호출된 다음에 초기화한다는 뜻

    • Kotlin은 클래스 안의 null이 될 수 없는 프로퍼티를 생성자 안에서 초기화하지 않고 특별한 메서드 안에서 초기화할 수 없다.
    • 초기화를 위해 null이 될 수 있는 타입을 사용하면 null 검사를 넣거나 !! 연산자를 써야 한다.
    • 나중에 초기화 하는 프로퍼티는 항상 var여야 한다.
    • 초기화 확인은 isInitialized
    • private lateinit var component: Object
          
      fun isInitialized() {
          if (::component.isInitialized) {        
          }
      }
    • Kotlin lazy property - lateinit/lazy 살펴보기
  4. 고차 함수 안에서 흐름 제어 
    • fun foo() {
          listOf(1, 2, 3, 4, 5).forEach {
              if (it == 3) return // non-local return directly to the caller of foo()
              print(it)
          }
          println("this point is unreachable")
      }
    • 람다 안에서 return을 사용하면 람다로부터만 반환되는 게 아니라 그 람다를 호출하는 함수가 실행을 끝내고 반환된다.
    • 자신을 둘러싸고 있는 블록보다 더 바깥에 있는 다른 블록을 반환하게 만드는 return을 넌로컬(non-local) return이라 부른다.
    • 로컬 return과 넌로컬 return을 구분하기 위해 레이블(label)을 사용해야 한다.
    • fun foo() {
          listOf(1, 2, 3, 4, 5).forEach {
              if (it == 3) return@forEach // local return to the caller of the lambda, i.e. the forEach loop
              print(it)
          }
          print(" done with implicit label")
      }

참고 자료

  • No labels