뭐라도 끄적이는 BLOG

Kotlin 변수와 데이터 타입 본문

Kotlin

Kotlin 변수와 데이터 타입

Drawhale 2023. 7. 1. 04:37

변수 선언 방법

모든 프로그램은 데이터를 저장할 수 있어야 하며, 변수를 사용하여 데이터를 저장할 수 있다. Kotlin에서는 2가지 키워드를 사용하여 변수를 선언한 수 있다.

  • val: 선언시에만 초기화가 가능하며 값을 변경할 수 없는 읽기전용 상수이다.
  • var: 일반적인 변수 선언 방법으로 언제든 읽기 쓰기가 가능한 방법이다.

기본적으로 변수는 읽기 전용으로 선언하는 것이 좋다.

val popcorn = 5// There are 5 boxes of popcorn
val hotdog = 7// There are 7 hotdogs
var customers = 10// There are 10 customers in the queue

// Some customers leave the queue
customers = 8
이 외에 클래스에 선언된 변수를 가르켜 Property라고 하며 Scope내에 선언된 변수를 Local 변수라고 한다.

타입 추론

변수를 선언할때 자료형을 넣어주지 않아도 된다. 이러한 타입 추론으로 코드양을 줄일 수 있다.

var string = ""

하지만 함수의 매개변수를 선언할때는 반드시 타입을 넣어주어야 되며 변수의 타입을 선언해 주었을때 이후 유지보수에서 도움이 되는 경우도 있어 특정 자료형으로 선언하는 방법은 반드시 알아두어야 한다.

Null Safety

일반적으로 기본 변수에서 null을 허용하지 않는다.

fun main(){
	var a: Int = 123
	println(a)
}

null을 허용할 수 있는 방법으로 자료형에 ?를 사용할 수 있다.

var a: Int? = null

기본 자료형

Kotlin의 모든 변수와 자료구조에는 자료형이 있다. 자료형은 컴파일러에 변수 또는 자료구조로 수행할 수 있는 작업을 알려주기 때문에 중요하다. Kotlin에서 모든 변수는 멤버 함수와 properties를 호출할 수 있다는 점에서 객체라고 할 수 있다. 일부 타입(numbers, characters, booleans는 런타임에 primitive 값으로 표현될 수 있다.)은 특별한 내부 표현을 가질 수 있지만 사용자한테는 일반 클래스처럼 보인다.

Kotlin에서 제공하는 기본 자료형은 아래와 같다.

Category Basic types
Integers Byte, Short, Int, Long
Unsigned integers UByte, UShort, UInt, ULong
Floating-point numbers Float, Double
Booleans Boolean
Characters Char
Strings String
val d: Int
d = 3

val e: String = "hello"

Numbers

Integer types

Kotlin은 숫자를 나타내는 built-in 타입을 제공한다. 정수 숫자의 경우 크기와 값 범위가 서로 다른 네 가지 타입이 있다.

Type Size (bits) Min value Max value
Byte 8 -128 127
Short 16 -32768 32767
Int 32 -2,147,483,648 (-231) 2,147,483,647 (231 - 1)
Long 64 -9,223,372,036,854,775,808 (-263) 9,223,372,036,854,775,807 (263 - 1)

명시적으로 타입을 지정하지 않고 변수를 초기화 하면 컴파일러는 값을 표현하기에 가장 작은 범위의 타입을 자동으로 추론한다. Long값을 명시적으로 타입을 지정하기위해서 값에 접미사 L을 추가해야 한다.

Unsigned integer types

Kotlin은 부호없는 정수에 대해 다음과 같은 타입을 제공한다.

Type Size (bits) Min value Max value
UByte 8 0 255
UShort 16 0 65535
UInt 32 0 2^32 - 1
ULong 64 0 2^64 - 1

부호없는 정수를 리터럴 값에 명시적으로 지정하기 위해서 접미사로 u또는 U를 사용한다.

 Floating-point types

Kotlin에서 실수의 경우 IEEE754표준을 준수하는 부동 소수점 유형 Float(단정밀도)와 Double(배정밀도)을 제공한다.

Type Size (bits) Significant bits Exponent bits Decimal digits
Float 32 24 8 6-7
Double 64 53 11 15-16
val e = 2.7182818284 // Double
val eFloat = 2.7182818284f // Float, actual value is 2.7182817

// val one: Double = 1 // Error: type mismatch
val oneDouble = 1.0 // Double

Float를 명시적으로 지정하려면 접미사 f또는 F를 추가해야한다.

Kotlin에는 다른 언어와 달리 숫자에 대한 암시적인 변환이 없다. 예를들어 Double 매개 변수가 있는 함수는 Double 값에 대해서만 호출할 수 있고 Float, Int등 다른 숫자 값에 대해서는 호출할 수 없다.

fun main() {
    fun printDouble(d: Double) { print(d) }

    val i = 1
    val d = 1.0
    val f = 1.0f

    printDouble(d)
//    printDouble(i) // Error: Type mismatch
//    printDouble(f) // Error: Type mismatch
}

숫자를 다른 타입으로 변환하기 위해서 명시적으로 변환해주어야 한다.

Literal constants for numbers

리터럴 상수 표현은 다음과 같다.

Type Size (bits)
Decimals 32
Longs are tagged by a capital L 123L
Hexadecimals 0x0F
Binaries 0b00001011
Doubles by default 123.5, 123.5e10
Floats are tagged by f or F 123.5f
8진수 표현은 지원하지 않는다.

언더바를 이용해서 숫자를 더 읽기 쉽게 만들 수 있다.

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

Explicit number conversions

작은 타입은 큰 타입의 하위 타입이 아니다. 만일 하위타입이라면 아래와 같은 문제가 발생한다.

// Hypothetical code, does not actually compile:
val a: Int? = 1 // A boxed Int (java.lang.Integer)
val b: Long? = a // Implicit conversion yields a boxed Long (java.lang.Long)
print(b == a) // Surprise! This prints "false" as Long's equals() checks whether the other is Long as well

결국 Kotlin에선 작은 타입은 암시적으로 큰 타입으로 변환되지 않기 때문에 명시적으로 변환이 필요하다.

val b: Byte = 1 // OK, literals are checked statically
// val i: Int = b // ERROR
val i1: Int = b.toInt()

모든 숫자 타입은 다른 타입으로 변환을 지원한다.

  • toByte(): Byte
  • toShort(): Short
  • toInt(): Int
  • toLong(): Long
  • toFloat(): Float
  • toDouble(): Double

JVM에서 숫자 표현

JVM에서 숫자는 int, double등과 같은 primitive tyupe으로 저장된다. Int?같은 null이 가능한 숫자와 제네릭을 사용하는 경우는 예외다. 이러한 경우 숫자는 java 클래스 Integer, Double등의 박스형으로 저장한다.

같은 숫자에서 Nullable참조는 서로 다른 객체를 참조할 수도 있다.

val a: Int = 100
val boxedA: Int? = a
val anotherBoxedA: Int? = a

val b: Int = 10000
val boxedB: Int? = b
val anotherBoxedB: Int? = b

println(boxedA === anotherBoxedA) // true
println(boxedB === anotherBoxedB) // false

a는 -128에서 127사이의 정수에 적용되는 JVM의 메모리 최적화 덕분에 실제로 동일한 객체가 된다. b는 적용되지 않아 서로 다른 객체가된다.

val b: Int = 10000
println(b == b) // Prints 'true'
val boxedB: Int? = b
val anotherBoxedB: Int? = b
println(boxedB == anotherBoxedB) // Prints 'true'

===가 아닌 ==으로 비교하면 같은 값을 가진다고 나온다.

숫자 연산

Kotlin은 숫자에 대한 표준 산술 연산을 지원한다. +, -, *, /, % 연산은 클래스 멤머로 선언되어 있다. 사용자는 이러한 연산자를 override할 수도 있다.

정수 나눗셈

일반적인 정수들끼리의 나눗셈은 정수를 반환한다. 결과를 부동 소수점 타입으로 받고 싶다면 인수중 하나를 부동 소수점 유형으로 명시적으로 변환해야 한다.

val x = 5 / 2            // 2
val y = 5 / 2.toDouble() // 2.5

비트연산

Int와 Long에만 비트 연산을 사용할 수 있다.

val x = (1 shl 2) and 0x000FF000
  • shl(bits) – signed shift left
  • shr(bits) – signed shift right
  • ushr(bits) – unsigned shift right
  • and(bits) – bitwise AND
  • or(bits) – bitwise OR
  • xor(bits) – bitwise XOR
  • inv() – bitwise inversion

부동 소수점 비교

  • Equality checks: a == b and a != b
  • Comparison operators: a < b, a > b, a <= b, a >= b
  • Range instantiation and range checks: a..b, x in a..b, x !in a..b
  • NaN is considered equal to itself
  • NaN is considered greater than any other element including POSITIVE_INFINITY
  • 0.0 is considered less than 0.0

Boolean

true, false 2가지 값을 가질 수 있다. ?키워드를 사용하여 null도 가능하다.

  • || – disjunction (logical OR)
  • && – conjunction (logical AND)
  • ! – negation (logical NOT)
val myTrue: Boolean = true
val myFalse: Boolean = false
val boolNull: Boolean? = null

println(myTrue || myFalse)
println(myTrue && myFalse)
println(!myTrue)

Characters

한가지 문자를 저장할 때 사용한다. Character의 리터럴은 작은 따옴포로 표시한다.

몇가지 특수문자는 escaping backslash로 시작한다. 이를 이스케이프 시퀀스라고 한다.

  • \t – tab
  • \b – backspace
  • \n – new line (LF)
  • \r – carriage return (CR)
  • \' – single quotation mark
  • \" – double quotation mark
  • \\ – backslash
  • \$ – dollar sign
val aChar: Char = 'a'

println(aChar)
println('\n') // Prints an extra newline character
println('\uFF00') //Unicode escape sequence syntax

val oneChar: Char = '1'
val tabChar: Char = '\t'
val backSpaceChar: Char = '\b'
val newLineChar: Char = '\n'
val singleQuotChar: Char = '\''
val doubleQuotChar: Char = '\"'
val backslashChar: Char = '\\'
val dollarChar: Char = '\$'

digitToInt를 사용하여 Int숫자로 변환할 수 있다.

String

Kotlin에서 문자열은 String 타입으로 표현된다. 일반적으로 문자열 값은 큰따옴표로 묶인 문자 시퀀스이다.

val str = "abcd 123"

문자열의 각 요소는 인덱스를 통해 엑세스할 수 있다. (s[i]) 문자열은 immutable이다. 문자열을 초기화하면 값을 변경하거나 새 값을 할당할 수 없다. 문자열을 변환하는 모든 연산은 원래 문자열이 변경되지 않은채 새로운 문자열을 반환한다.

val str = "abcd"
println(str.uppercase()) // Create and print a new String object
println(str) // The original string remains the same

문자열을 연결하려면 + 연산자를 사용한다. 표현식의 첫 번째 요소가 문자열인경우 다른 타입의 값과 문자열을 연결할 때도 사용할 수 있다.

val s = "abc" + 1
println(s + "def")

Raw strings

Raw strings는 개행과 임의의 텍스트가 포함될 수 있다. Raw strings는 큰따옴표 3개(""")로 생성할 수 있다.

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

Raw string을 사용하면 여러줄 개행시 가독성을 위해 다른 줄과 들여쓰기를 같게 해야할때가 있다. 이때 들여쓰기 공백을 제거하려면 trimMargin()함수를 사용한다.

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

기본적으로 파이프 기호(|)가 여백 접두사로 사용되지만 다른 문자를 선택하여 trimMargin(">")과 같이 매개변수로 전달할 수 있다.

String template

문자열 리터럴에 템플릿 표현식이 포함될 수 있다. 템플릿 표현식은 달러기호($)로 시작한다.

val i = 10
println("i = $i") // Prints "i = 10"

템플릿은 원시 문자열과 이스케이프된 문자열 모두 사용할 수 있다. 식별자의 시작 부분으로 허용되는 기호 앞에 달러 기호 $를 사용하면 된다.

fun main() {
    val number = 10000
    val price = """
        |${number}
    """.trimMargin()
    println(price)
}

Arrays

Kotlin의 배열은 Array 클래스로 표현된다. 이 클래스에는 연산자 오버로딩에 따라 [](인덱스 방식)로 변환되는 get()및 set()함수와 크기 속성 및 기타 유용한 멤버 함수가 있다.

class Array<T> private constructor() {
    val size: Int
    operator fun get(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요소로 채워진 지정된 크기의 배열을 만들수도 있다.

// Creates an Array<String> with values ["0", "1", "4", "9", "16"]
val asc = Array(5) { i -> (i * i).toString() }
asc.forEach { println(it) }

Kotlin의 배열은 불변이다.

Primitive type arrays

Kotlin에는 boxing 오버헤드 없이 Primitive 타입의 배열을 나타내는 클래스도 있다. ByteArray, ShortArray, IntArray등이 있다. 이러한 클래스는 Array 클래스와 상속 관계는 없지만 동일한 메서드 및 프로퍼티를 갖고 있다.

val x: IntArray = intArrayOf(1, 2, 3)
x[0] = x[1] + x[2]
// Array of int of size 5 with values [0, 0, 0, 0, 0]
val arr = IntArray(5)

// Example of initializing the values in the array with a constant
// Array of int of size 5 with values [42, 42, 42, 42, 42]
val arr = IntArray(5) { 42 }

// Example of initializing the values in the array using a lambda
// Array of int of size 5 with values [0, 1, 2, 3, 4] (values initialized to their index value)
var arr = IntArray(5) { it * 1 }

 

Get started with Kotlin | Kotlin

 

kotlinlang.org

반응형

'Kotlin' 카테고리의 다른 글

Kotlin Lambda  (0) 2023.07.03
Kotlin 함수  (0) 2023.07.03
Kotlin 제어문(조건문: if/when, 제어문: for/while)  (0) 2023.07.01
Hello Kotlin  (0) 2023.06.30