Skip to content

배토의 개발일지

나를위한 단편적 기억들의 기록

Menu
  • 안드로이드
  • 코틀린
  • Godot
  • 블렌더
  • git
  • 게임제작일지
  • 기타
Menu

Kotlin 에 익숙해지기 : 낯선 문법들 정리 #1

Posted on 2024년 10월 6일2024년 10월 7일 by batmask

when 문 : https://kotlinlang.org/docs/control-flow.html#when-expression

최신 언어들은 switch-case 문을 안쓰는 추세다. 대신 더 유연하고 진보적인 when문이 생김. when문은 switch-case와 유사하게 조건 표현식에 따라 여러 경우의 수에 대해 처리를 달리 해주는 표현식이다.

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> {
        print("x is neither 1 nor 2")
    }
}

swich 문과 다르게 break나 continue가 없다. 대신 순차적으로 조건을 체크하면서 만족하는 브랜치를 찾아 실행하게 된다. when은 그냥 statement로도 쓰일 수 있지만, expression으로 사용될 수도 있다. 이 경우, 조건식의 마지막 expression값이 리턴값이라고 생각하면 된다. 또한, 나열되는 조건이 모든 가능한 조건을 포함하는 경우, else는 생략될 수 있다.

enum class Bit {
    ZERO, ONE
}

val numericValue = when (getRandomBit()) {
    Bit.ZERO -> 0
    Bit.ONE -> 1
    // 'else' is not required because all cases are covered
}

여러 케이스를 합치는 경우엔 콤마(,)로 컨디션을 한 라인에 나열 할 수 있다.

when (x) {
    0, 1 -> print("x == 0 or x == 1")
    else -> print("otherwise")
}

조건부분에 임의의 표현식 사용도 가능하다.

when (x) {
    s.toInt() -> print("s encodes x")
    else -> print("s does not encode x")
}

in, !in 을 이용해 range 체크도 가능.

when (x) {
    in 1..10 -> print("x is in the range")
    in validNumbers -> print("x is valid")
    !in 10..20 -> print("x is outside the range")
    else -> print("none of the above")
}

is, !is를 이용해 타입 체크도 가능.

fun hasPrefix(x: Any) = when(x) {
    is String -> x.startsWith("prefix")
    else -> false
}

인자 없이 if-else 체인을 대신해서 사용도 가능하다.

when {
    x.isOdd() -> print("x is odd")
    y.isEven() -> print("y is even")
    else -> print("x+y is odd")
}
seperator

for 문 : https://kotlinlang.org/docs/control-flow.html#for-loops

for 루프도 C나 자바처럼 초기치; 조건; 증가분 형태가 아니라 파이썬같은 방식으로 사용된다. 제공되는 iterator에 대해서 순회하는 방식이다. 이는 C#의 foreach문과 동일하다.

for (item in collection) print(item)

for (item: Int in ints) {
    // ...
}

주어진 iterator를 이용한다는 얘기는 리턴값이 Iterator<>인 iterator() 도 멤버로 갖고 있거나 확장함수로 가져야 한다. 또한, next()와 hasNext()를 멤버로 갖거나 확장함수로 갖고 있어야 한다.

range 표현식을 사용하는 경우의 예는 다음과 같다.

for (i in 1..3) {
    println(i)
}
for (i in 6 downTo 0 step 2) {
    println(i)
}

array나 list의 인덱스로 순회하는 경우의 예는 다음과 같다.

for (i in array.indices) {
    println(array[i])
}

이걸 withIndex를 사용하여 다음과 같이 사용하면 index와 value를 보다 가독성이 좋게 사용 가능하다.

for ((index, value) in array.withIndex()) {
    println("the element at $index is $value")
}
seperator

extention function : https://kotlinlang.org/docs/extensions.html

기존 클래스에 새 기능을 넣으려면 상속(inheritance)을 받아 구현하는게 보통이다. 아니면 기존 클래스를 포함하는 새 클래스를 만들고 그 멤버로 기존 클래스를 생성하는 composition, 또는 새 클래스의 생성자의 인자로 기존 클래스를 넘겨서 멤버에 저장하는 Aggregation을 이용할 수도 있다. Decorator 패턴은 Aggregation을 이용하게 되는데, 코틀린에서는 Extension function을 이용해 이를 손쉽게 구현할 수 있다.

Extension function은 리시버 타입 클래스를 지정하고 함수를 정의한다.

fun MutableList<Int>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // 'this' corresponds to the list
    this[index1] = this[index2]
    this[index2] = tmp
}

val list = mutableListOf(1, 2, 3)
list.swap(0, 2) // 'this' inside 'swap()' will hold the value of 'list'

만약, 기존에 갖고있는 멤버함수와 동일하게 확장함수를 정의하면 항상 멤버함수가 불리게 된다. 이와 동일하게 property도 extension property 사용이 가능하다.

val <T> List<T>.lastIndex: Int
    get() = size - 1
seperator

Class Constructors : https://kotlinlang.org/docs/classes.html#constructors

기본적으로 primary constructor는 클래스 선언에 ‘constructor’ 키워드와 함께 사용한다. annotation이나 visibility modifier 가 없다면, 키워드는 생략이 가능하다.

class Person constructor(firstName: String) { /*...*/ }
class Person(firstName: String) { /*...*/ }

이렇게 쓰면, 생성자 바디가 없는 상태인데, 클래스 안에서 init { } 블럭을 이용해 생성자 코드를 사용할 수 있다.

class InitOrderDemo(name: String) {
    val firstProperty = "First property: $name".also(::println)
    
    init {
        println("First initializer block that prints $name")
    }
    
    val secondProperty = "Second property: ${name.length}".also(::println)
    
    init {
        println("Second initializer block that prints ${name.length}")
    }
}

이 init { } 블럭은 인스턴스 생성시, 기술된 순서대로 실행된다. 또한, property 초기화도 생성자로 사용된다.

class Customer(name: String) {
    val customerKey = name.uppercase()
}

좀 더 간편하게, primary 생성자에 property들을 직접 기술 할 수 있다. 마지막에 콤마가 있어도 상관없다.

class Person(val firstName: String, val lastName: String, var age: Int,)

primary constructor 외에 추가로 생성자가 필요하다면, 클래스 바디안에 constructor 키워드를 이용해 선언한다. primary constructor가 존재한다면, secondary constructor는 primary constructor에 delegate해야한다.

class Person(val name: String) {
    val children: MutableList<Person> = mutableListOf()
    constructor(name: String, parent: Person) : this(name) {
        parent.children.add(this)
    }
}

this를 사용하면 되며, 위 코드에서 this(name)이 사용되었다.

답글 남기기 응답 취소

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

최신 글

  • Blender : snap을 써서 다른 vertex에 정렬하기
  • KTor Client 기본 사용 정리
  • 게임 만들거다.
  • Using Koin with Android Compose

보관함

2024 10월
일 월 화 수 목 금 토
 12345
6789101112
13141516171819
20212223242526
2728293031  
« 7월   12월 »

메타

  • 로그인
  • 엔트리 피드
  • 댓글 피드
  • WordPress.org
©2025 배토의 개발일지 | Built using WordPress and Responsive Blogily theme by Superb