Kotlin – 기초(1)

공식 문서 정리 중

기본 타입

Kotlin에서는 모든 것이 객체이고 따라서 모든 변수의 멤버 함수나 프로퍼티를 호출할 수 있다. 몇몇 타입은 내장되어 있어 사용자들에게는 일반적인 클래스들이 있다. 이 섹션에서는 이런 타입의 대부분을 차지하고 있는 numbers, characters, booleans, arrays를 살펴본다

Numbers

Kotlin에서는 숫자들을 Java와 매우 유사하게 다루지만 완전히 동일한 방식은 아니다. 예를 들어 숫자 타입에 대한 암묵적 범위 확장을 지원하지 않고 리터럴도 몇몇 다른 경우가 있다

암묵적 확장 (implicit widening conversion) : int 타입의 변수와 long 타입의 변수를 비교할 때 암묵적으로 int타입의 변수를 long타입으로 변환한 후 비교하게 된다

Kotlin은 아래의 숫자를 표현하는 빌트인 타입을 지원한다 (자바와 매우 유사함)

Type Bit width
Double 64
Float 32
Long 64
Int 32
Short 16
Byte 8

Kotlin에서는 Character는 Number가 아님을 주의하라

상수 리터럴

  • 10진수: 123
    • Long 타입은 뒤에 대문자 L을 붙인다 : 123L
  • 16진수: 0x0F
  • 2진수: 0b00001011

8진수 리터럴은 지원하지 않음

  • Floating point
    • 기본은 Double : 123.5, 123.5e10
    • Float는 F 혹은 f를 뒤에 붙인다 : 123.5f

숫자 리터럴에 언더바 사용하기 (1.1 부터)

숫자 리터럴에 언더바를 사용해서 가독성을 높일 수 있다

val oneMillion = 1_000_000
val creditCardNumber = 1234_5678_9012_3456L
val socialSecurityNumber = 999_99_9999L
val hexBytes = 0xFF_EC_DE_5E
val bytes = 0b11010010_01101001_10010100_10010010

Representation

자바 플랫폼에서 null 레퍼런스를 사용하거나 제네릭을 사용하지 않는다면 숫자는 물리적으로 primtive type으로 저장된다. 후자의 경우 숫자는 boxing된다

숫자의 boxing은 아이덴티티를 반드시 유지(동일한 메모리 주소를 가짐)하는 것은 아니라는 점을 주의하자 ( === 연산자 사용 )

val a: Int = 10000
print(a === a) // Prints 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA === anotherBoxedA) // !!!Prints 'false'!!!

하지만 값은 동일하다 ( == 연산자 사용 )

val a: Int = 10000
print(a == a) // Prints 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA == anotherBoxedA) // !!!Prints 'true'!!!

명시적 변환

서로 다른 표현 방식으로 인해 작은 범위의 타입(이를테면 Int)은 큰 범위 타입(이를테면 Long)의 서브 타입이 아니다. 만약 그랬다면 아래와 같은 코드에서 문제가 발생할 것이다.

// 가상의 코드이다. 실제로는 컴파일되지 않는다
val a: Int? = 1     // boxed Int (java.lang.Integer)
val b: Long? = a    // 암묵적 conversion이 발생하여 boxed Long (java.lang.Long)이 된다
print(a == b)       // false가 출력된다. Long의 equals 메서드는 비교할 인자의 타입으로 Long을 기대하기 때문이다

따라서 아이덴티티 뿐만 아니라 값 비교에서도 문제가 발생한다

결과적으로 작은 범위의 숫자 타입은 큰 범위의 숫자 타입의 섭 타입이 아니다. 이것은 Byte 타입에 대입한 값을 명시적 변환 과정 없이 다시 Int 타입에 대입할 수 없다는 것을 의미한다.

val b: Byte = 1 // OK, literals are checked statically
val i: Int = b // ERROR

// 명시적 변환을 이용한 대입
val i: Int = b.toInt()      // OK

각 숫자 타입은 아래와 같은 명시적 변환을 지원한다

  • toByte()
  • toShort()
  • toInt()
  • toLong()
  • toFloat()
  • toDouble()
  • toChar()

암묵적 변환 과정의 부재는 거의 알아채기 힘든데, 그 이유는 타입은 컨텍스트를 통해 추론되며 수학적 연산은 적당한 과정으로 오버로딩되기 때문이다. 예를 들어

val l = 1L + 3      // Long + Int => Long

연산자

Kotlin 적절한 클래스의 멤버로서 선언된 숫자 타입 데이터들에 대해 표준 연산자 세트를 지원합니다. 연산자 오버로딩을 참조하세요

비트 연산에 대해서 특별한 기호는 없지만 중위 표현(infix notaion)을 사용해서 함수를 호출 할 수 있습니다. 예를 들어

val x = (1 shl 2) and 0x000FF000

아래는 비트 연산 함수들의 목록입니다. (Int 및 Long 타입만 지원)

  • shl(bits) – signed shift left (자바의 <>)
  • ushr(bits) – unsigned shift right (자바의 >>>)
  • and(bits) – bitwise and
  • or(bits) – bitwise or
  • xor(bits) – bitwise xor
  • inv() – bitwise inversion

Character

캐릭터는 Char 타입으로 표현됩니다. Char 타입은 바로 숫자로 처리될 수 없습니다.

fun check(c: Char) {
    if (c == 1) {       // ERROR: incompatible type

    }
}

캐릭터 리터럴은 홑따옴표로 표현됩니다. ('1') 특수 문자는 역슬래쉬로 이스케이프합니다. \t, \b, \n, \r, \', \", \\, \$ 이스케이프 문자를 지원합니다. 다른 캐릭터를 인코딩하기 위해서는 유니코드의 이스케이프 시퀀스 문법을 사용합니다 (\uFF00)

캐릭터는 명시적으로 Int 타입으로 변환할 수 있습니다.

fun decimalDigitValue(c: Char): Int {
    if (c !in '0'..'9') {
        throw IllegalArgumentException("Out of Range")
    }
    return c.toInt() - '0'.toInt()      // 명시적으로 Int 타입으로 변환
}

숫자와 유사하게 캐릭터 역시 nullable 레퍼런스가 필요한 경우 boxing됩니다. boxing 연산 후 서로 다른 아이덴티티(변수의 메모리 주소)를 갖게 됩니다. (Identity is not perseved by boxing operation)

Booleans

booleans는 true/false 두 값만을 가진 Boolean 타입으로 표현됩니다.

Boolean 타입은 nullable 레퍼런스가 필요할 때 boxing 됩니다.

Boolean 타입에 대한 내장 연산자는 다음과 같습니다.

  • || – lazy disjunction
  • && – lazy conjunction
  • ! – negation

배열

코틀린에서의 배열은 Array타입으로 표현됩니다. get, set, size 메소드를 사용할 수 있고 연산자 오버로딩 컨벤션에 의해 []로 아이템에 접근할 수 있습니다. 다음은 몇 가지 유용한 멤버 함수들입니다.

class Array<T> private constructor() {
    val size: Int
    operator fun set(index: Int): T
    operator fun set(index: Int, value: T): Unit

    operator fun iterator(): Iterator<T>
}

배열을 생성하려면 arrayOf라는 내장 함수에 값들을 넘겨 호출합니다. 따라서 arrayOf(1,2,3)은 배열 [1,2,3]을 생성합니다. 또한 arrayOfNulls 내장 함수를 이용하여 null로 채워진 배열을 생성할 수도 있습니다.

또 다른 방법으로는 배열의 크기와 초기 값을 리턴하는 함수를 인자로 받는 Factory 함수를 사용하는 것입니다.

// ["0", "1", "4", "9", "16"]의 배열을 생성
val as = Array(5, { i -> (i * i).toString() })

위에서 언급한대로 [] 연산자를 이용해 get, set 함수를 대신할 수 있습니다.

주의: 자바와는 다르게 코틀린에서의 배열은 불변(invariant)입니다. 이것은 런타임에 발생할 수 있는 오류를 방지하기 위해서 ArrayArray를 할당할 수 없다는 것을 의미합니다. (그러나 Array를 사용할 수는 있습니다. Type projections를 참조하세요

코틀린은 boxing 부하를 없이 primitive 타입의 배열을 사용하기 위해 몇 가지 특별한 클래스를 제공합니다 – ByteArray, ShortArray, IntArray 등등. 이 클래스들은 Array 클래스와 상속 관계가 아니나 동일한 메서드와 프로퍼티를 가집니다. 각 클래스는 대응되는 팩토리 함수도 가지고 있습니다.

val x: IntArray = intArrayOf(1,2,3)
x[0] = x[1] + x[2]

String

String 타입은 문자열은 표현합니다. String은 불변 객체입니다. 문자열의 각 글자는 []를 이용해서 인덱스로 접근할 수있습니다. for 루프에서 문자열을 사용할 수 있습니다.

for(c in str) {
    println(c)
}

문자열 리터럴

코틀린은 이스케이프 문자가 포함된 이스케이프 문자열과 일반 문자열 2가지 타입의 문자열 리터럴을 지원한다. 이스케이프 문자열은 자바와 매우 흡사하다

val s = "Hello, world!\n"

이스케이프 처리는 역슬래시를 이용한 일반적인 방법으로 이루어진다. 캐릭터 페이지에서 지원하는 이스케이프 문자를 확인할 수 있다

raw 문자열은 쌍따옴표 세개를 사용해서 구분하는데 이스케이프할 수 없고 개행 문자 및 다른 일반 문자들을 포함할 수 없다

val text = """
    for (c in "foo")
        print(c)
"""

맨 앞의 공백을 trimMargin() 함수로 제거할 수 있다

val text = """
    |Tell me and I forget.
    |Teach me and I remember.
    |Involve me and I learn.
    |(Benjamin Franklin)
    """.trimMargin()

margin prefix의 기본 문자는 |이지만 trimMargin("&gt;")처럼 다른 문자를 파라미터로 전달해서 사용할 수도 있다

문자열 템플릿

문자열은 템플릿 표현식을 가질 수 있다. 템플릿 표현식은 $문자로 시작되고 단순 이름을 포함한다

val i = 10
val s = "i = $i"         // i = 10으로 평가됨

혹은 중괄호 {}를 사용해서 연산 표현식을 사용할 수도 있다

val s = "abc"
val str = "$s.length is ${s.length}     // abc.length is 3

템플릿 표현식은 raw 문자열과 이스케이프된 문자열에서 모두 사용할 수 있다. $문자열 그대로를 raw 문자열에서 사용하고 싶다면 (\는 지원하지 않으므로) 다음처럼 사용할 수 있다

val price = """
${'$'}9.99
"""

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

w

%s에 연결하는 중