본문 바로가기

코틀린

[Kotlin] 기본 타입

코틀린에서 지원하는 타입들은 통상적으로 Java의 것을 따라간다.

  • Numbers : 숫자
    • Integer
    • Float
  • Booleans : 불린
  • Characters : 문자
  • Strings : 문자열
  • Arrays : 배열
  • Unsigned Integer : 부호 없는 정수 타입. Java 에 unsigned 예약어가 없는 것처럼, 코틀린에서도 부호 없는 정수 타입을 만들 때 unsigned 를 사용하지 않는다.

Number

 정수 타입과 실수 타입이 있다. 

정수 타입

타입 크기 ( bit ) 타 언어 unsigned
Byte 8 byte / char UByte
Short 16 short UShort
Int 32 int UInt
Long 64 long ULong

자바 언어처럼 숫자 및 문자에 대한 1 byte 크기의 자료형을 분리해서 가진다. 8진법 표기는 지원하지 않는다.

 Int 타입 및 Long 타입에 대해서는 비트 연산이 가능하다. 통상적인 비트연산자 대신 코틀린이 가진 비트 연산 함수를 통해서만 비트 연산을 수행할 수 있다.

함수 연산자 설명
shl << 좌측으로 비트 이동 
shr >> 우측으로 비트 이동 
ushr >>> 부호 고려 없이 우측으로 비트 이동
and & bitwise AND
or | bitwise OR
xor ^ bitwise XOR
inv ~ bitwise inversion

실수 타입

타입 크기 ( bit ) 가수부 지수부 타 언어 비고
Float 32 24 8 float IEEE 754 표준을 따른다.
Double 64 53 11 double  

 타입을 명시하는 경우, 소수점 혹은 F를 표기하여 해당 타입이 실수 타입임을 명시적으로 보여야 한다. 그렇지 않으면 아래처럼 에러가 발생한다. 타입을 명시하지 않는 경우 알아서 추론한다.

 실수끼리의 비교 방법은 다음과 같다.

비교 기호
Equality a == b , a != b
Conparision a > b , a < b , a >= b , a <= b
Range x in a..b , a !in a..b

파이썬처럼 range 비교가 가능하다는 특징이 있다.

Boolean

 통상적인 연산자를 이용한다.

  • || ( disjunction ) , && ( conjuction ), ! ( negation )
  • 앞에서부터 검사하여 조건을 만족하면 뒷 부분은 검사하지 않는다 ( lazy ) .

Character

 통상적인 char 형의 특징을 따른다. 

  • ' ' ( 작은 따옴표 ) 로 감싼 문자
  • \_ 형식을 통해 특수기호 표현 가능

String 

 " " ( 큰 따옴표 ) 를 이용하여 표현한다. 문자의 배열로 간주되어 for문을 통해 문자 단위로 순회할 수 있으나, 불변 타입이므로 한번 생성하면 변경할 수 없다. 만약 문자 단위로 변경하려고 하면 다음과 같은 에러가 발생한다.

 이는 문자 각각에 대한 set 함수가 정의되어 있지 않기 때문으로 보인다. 이러한 이유로 문자열을 조작하는 경우 원본 문자열은 그대로 있고, 새로운 문자열이 생성되는 방식으로 동작한다.

raw string

 문자열을 여러줄로 나타내고 싶은 경우에는 """ """ 을 이용한다.

 단순히 """ 만을 이용하면 들여쓰기에 어떤 수정도 가하지 않아 예상하지 못한 들여쓰기가 나타날 수 있다. 이러한 현상을 수정하는 방법은 2가지가 있다.

  • trimMargin("str") : str을 기준으로 앞의 들여쓰기를 무시한다.
  • trimIndent() : 알아서 들여쓰기를 인식하여 최소값을 기준으로 수정한다.

trimMargin
trimIndent

string template

자바와는 달리, 코틀린은 문자열 템플릿이 기본 지원된다.

val cost : Int = 100
println("the cost is $cost")

val arr = IntArray(5) { i -> (i * 2 + 1)}
println("the length of arr is ${arr.size}")

println("\$ or ${'$'}")

출력된 결과

  • $ 또는 ${ } 을 이용하여 템플릿을 나타낸다.
  • '$' 기호 자체를 표기하고 싶은 경우 '\$' 또는 ${'$'} 으로 나타낸다.

 $ 기호 뒤에 어떤 $을 제외한 문자가 오는 경우 템플릿으로 간주하는 것으로 보인다. 따라서 안정적인 코딩을 위해서는 \$ 방식으로 표기하는 것이 좋다.

Array

 코틀린의 Array 클래스에 의해 정의되며, 크기를 변경할 수 없다.

val arr1 = Array<Int>(5) {i -> (i * 2 + 1)}
val arr2 = arrayOf<Int>(1,3,5,7,9)
val arr3 = arrayOf("A", 1, 10f, 'c')
val arr4 = intArrayOf(1,2,3,4,5) // primitive type

 arrayOf 함수를 통해 생성하거나, Array + lambda 함수 구조로 구현할 수 있다. 이 방식을 이용하면 기본적으로 값이 박싱되므로, 성능을 위해서는 intArrayOf , doubleArrayOf 등 primitive type 에 대해 미리 설정된 함수를 이용해야 한다.

 예를 들어 위 코드를 자바로 디컴파일하면 다음과 같은 결과가 나온다.

 arr1 및 arr2 는 Int 형이라고 명시했음에도 불구하고 int 형의 wrapper class인 Integer의 배열 형태로 생성되고 있으며, 여러 타입이 섞인 arr3 는 Object 의 배열이 되었다. 반면 intArrayOf 을 통해 생성한 arr4 ( = var10 ) 배열은 의도대로 int[ ] 형식으로 생성되었다.

 따라서 배열이 primitive type으로만 구성되는 경우 반드시 _ArrayOf 함수를 이용하여 생성하는 것이 좋다.

Unsigned Integer

 초기 자바에서는 unsigned 을 지원하지 않았고, 현재도 타 언어에 비해 매끄럽게 지원되는 편은 아니다. 코틀린은 자바와 동일한 JVM 환경 아래에서 동작하나, 신기하게도 부호 없는 정수 및 정수 배열 기능을 지원한다. 

 단, 코틀린의 unsigned 변수는 C / C++ 과 같은 언어들에서 단순히 첫 비트의 인식 방식에 관련된 것과는 달리 내부 클래스를 생성하여 구현하기 때문에 통상적인 부호 없는 정수형과는 큰 차이가 있다. 아래 코드를 보자.

코틀린 코드(좌) 와 해당 코드를 자바 코드로 디컴파일한 결과(우)

  코틀린의 unsigned 형은 코틀린 내부 클래스인 UInt, UByte 등 언어를 이용하여 int 형을 박싱한 형태로, 실제로 해당 변수가 unsigned 로 사용되는 시점에 값을 내부 클래스로 박싱하여 사용하게 된다.  

 위 코드에 따르면 초기 UInt 로 선언된 a는 자바 코드 기준 단순한 int 형 변수로 관리된다. UInt 변환이 발생하는 시점은 println 을 통해 변수의 내용을 출력하는, 실제로 UInt 관련 동작을 수행하는 때이다. arr1 역시 UIntArray임에도 불구하고 내부적으로는 단순히 int[ ] 로 관리되며, UInt 관련 동작을 수행하는 시점에 박싱을 통해 값을 변경한다.

 위 코드는 for 문 내부에서 UIntArray의 각 변수 상대로 덧셈 및 출력을 진행한 코드이다. 실제 값은 단순히 int 형으로 관리되며, UInt 관련 동작을 수행하는 시점에만 get & set 을 통해 부호 없는 정수 타입으로 대한다.

타입 체크 및 캐스팅

 코틀린은 모든 클래스의 조상격이 되는 Any 클래스를 지정해두고 있어, 입력으로 여러 타입이 오는 함수도 만들 수 있다. Any를 파라미터로 가지는 경우 들어오는 인자가 어떤 값인지 알기 위한 타입 체크 및  실 사용을 위한 캐스팅을 수행해야 하는데, 여기에 각각 is 와 as 가 사용된다.

fun main() {
    checkStringLen(13, 3)
    checkStringLen("This is Apple", 3)
}

fun checkStringLen(arg: Any, len: Int) {
    if(arg !is String)
    {
        println("$arg is not a string!")
    }
    else{
        if (len >= arg.length)
        {
            println("$len is enough for arg")
        }
    }
    val str : String? = arg as? String;

    println("$str")
}

위 코드의 if 문에서는 !is 을 통해 입력된 arg가 문자열이 아닌지 여부를 검사한다. 컴파일러는 if문 조건을 만족하지 않으면 arg가 문자열이라는 사실을 알고 있으므로, smart cast을 통해 else 문에서 arg을 String 타입으로 간주한다. 따라서 대부분의 경우 명시적으로 형변환을 수행할 필요가 없다.

 str은 as 을 통해 String 형으로 명시적 형변환된다. as 는 불가능한 형변환을 수행하는 경우 예외를 발생시키는데, 코틀린에서는 as? 을 따로 둬서 형변환에 실패하는 경우 null을 넣는다.

 

'코틀린' 카테고리의 다른 글

[코틀린] 자바&코틀린 라이브러리 검색  (0) 2022.11.05
[Kotlin] 상속  (0) 2022.10.10
[Kotlin] 생성자  (0) 2022.09.06
[Kotlin] control flow  (0) 2022.09.06
[Kotlin] 기본 타입과 내부 처리  (0) 2022.09.01