Language/Kotlin

변수와 함수 Kotlin

JunOnJuly 2024. 7. 4. 00:28
728x90

변수의 선언

코틀린에서는 변수를 val, var 키워드로 사용합니다.

val 은 value 의 줄임말초깃값이 선언된 후 바꿀 수 없는 변수를 선언할 떄 사용하고

var 은 variable 의 줄임말초깃값이 선언된 후 바꿀 수 있는 변수를 선언할 때 사용됩니다.

val num1 = 10
var num2 = 10

fun main() {
	num1 = 20 // -> 실패
    num2 = 20 // -> 성공
}

타입 지정과 타입 추론

변수명 뒤에는 콜론을 추가해 타입을 명시할 수 있으며 값에 따라 타입을 추론할 수 있을때는 생략할 수 있습니다.

val num1: Int = 10
val num2 = 10

초깃값 할당

최상위에 선언한 변수나 클래스의 멤버 변수선언, 초깃값 설정이 동시에 이루어져야 합니다.

하지만 함수 내부에서 선언한 변수선언과 초깃값 선언이 분리되어도 괜찮습니다. 다만 변수로 사용하려면 값을 할당해야 합니다.

 

하지만 변수를 선언할 때 초깃값을 선언하지 못하는 경우에는 lateinit 이나 lazy 키워드를 사용해 컴파일러에게 알려주면 이후에 초깃값을 할당할 수 있습니다.

 

다만 lateinit 은 var 키워드로 선언한 변수에만 사용할 수 있으며 Int, Long, Short, Double, Float, Boolean, Byte 타입에는 사용할 수 없습니다.

 

lazy 키워드는 변수 선언문 뒤에 by lazy {} 형식으로 선언되는데, 소스에서 변수가 최초로 사용되는 순간 자동으로 실행되며 결괏값이 변수의 초깃값으로 할당됩니다. 또한 중괄호 부분이 여러 줄이라면 마지막 줄의 실행 결과가 변수의 초깃값이 됩니다.

val num1 : Int // -> 실패 : 초깃값 설정을 하지 않음
val num2 = 10 // -> 성공

fun testFun() {
	val num3: Int // -> 성공
    println("num3 : $num3") // -> 실패 : 함수 값이 존재하지 않음
    num3 = 10
    println("num3 : $num3") // -> 성공
}

class testClass {
	val num4: Int // -> 실패 : 클래스의 맴버 변수는 선언과 초깃값 할당이 동시에 이뤄져야함
    val num5: Int = 10 // -> 성공
}

lateinit var num6: Int // -> 실패 : Int 형
lateinit val num7: String // -> 실패 : val 키워드
lateinit var num8: String // -> 성공

val num9: Int by lazy {
	println("lazy..")
    10
}

fun testLazy() {
	println(num9 + 10)
    println(num9 + 10)
}

/* 실행 결과
lazy..
20
20
*/

데이터 타입

코틀린의 모든 변수는 객체입니다. 즉 모든 데이터 타입은 객체 타입입니다. 때문에 여러 타입의 변수에 null을 대입할 수도 있습니다.

fun testFun() {
    var num1: Int? = null // -> 성공
    var num2: Int = 10
    
    data1 = data1.plus(10) // -> 객체 메서드 사용 가능
}

 

기초 타입 객체에는 Int, Short, Long, Double, Float, Byte, Boolean 이 있습니다.

문자와 문자열의 객체에는 Char 와 String 이 있습니다. Char 은 작은 따옴표로, String 은 큰 따옴표나 삼중 따옴표로 감싸서 표현합니다.

 

String 타입의 데이터에 변수나 연산식의 결괏값을 사용하고 싶다면 $ 기호를 사용하는데 이를 문자열 템플릿이라고 합니다.

fun testFun {
	val str1 = "Hello"
    val str2 = """
    	Hello
        Hello
    """
    println("str1 : $str1")
    println("str2 : $str2")
}

/* 실행결과
Hello
		Hello
		Hello
*/

Any, Unit, Nothing, 널 허용 / 불허용

Any 는 최상위 클래스로, 모든 클래스는 Any의 하위 클래스입니다. 즉 Any 타입으로 선언한 변수에는 모든 타입의 데이터를 할당할 수 있습니다.

val num1: Any = 10
val str1: Any = "Hello"

class Cls
val cls1: Any = Cls()

Unit 은 데이터의 형식이 아닌 특수한 상황을 표현하는데 쓰입니다. Unit 으로 선언한 객체에는 Unit 객체만 대입할 수 있으므로 선언에 의미가 없습니다. 이는 함수에서 반환문이 없음을 명시적으로 나타낼 때 쓰입니다. 또 반환 타입을 생략하면 자동으로 Unit 이 적용됩니다.

val unit1: Unit = Unit

fun test(): Unit {
	printle(10)
}

Nothing 또한 Unit 처럼 특수한 상황을 표현하는데 쓰입니다. Nothing 으로 선언한 객체에는 null 만 대입할 수 있습니다. 그래서 Nothing 으로 선언한 변수 역시 선언에 의미가 없습니다. Nothing 역시 함수의 반환 타입에 사용되는데, 반환은 하지만 의미있는 값은 아니라는 의미입니다. 항상 null 을 반환하거나 예외를 던지는 함수의 반환 타입을 Nothing 으로 선언합니다.

val num1: Nothing? = null

fun test1(): Nothing? {
	return null
}

fun test2(): Nothing {
	throw Exception()
}

코틀린에서 모든 타입은 객체이므로 변수에 null 을 대입할 수 있습니다. 다만 null 은 값이 할당되지 않는 상황을 의미합니다. 그래서 코틀린에서는 변수를 선언할 때 null 을 대입할 수 있는 변수인지 아닌지 명확하게 구분해야 합니다. 변수를 선언할 때 물음표를 표시하면 널을 허용한다는 의미고 추가하지 않으면 불허용으로 선언합니다.

var num1: Int = 10
num1 = null // -> 실패

var num2: Int? = 10
num2 = null // -> 성공

함수 선언하기

코틀린에서 함수를 선언하기 위해서는 fun 이라는 키워드를 사용합니다.

fun {함수명}( {매개변수명}: {타입} ):  { 반환타입 } {...}

 

함수에는 반환 타입을 선언할 수 있고 생략하면 Unit 타입이 적용됩니다.

 

함수의 매개변수에는 var 이나 val 키워드를 사용할 수 없고 val 이 자동으로 적용됩니다. 즉 함수 안에서 매개변숫값을 변경할 수 없습니다.

fun test1(num1: Int): Int {
	return num1 + 10
}

fun text2(num1: Int) {
	num1: 20 // -> 실패
}

함수의 매개변수에는 기본값을 선언할 수 있고 기본값을 선언했다면 호출할 때 인자를 전달하지 않아도 됩니다.

fun test(num1: Int, num2: Int = 10): Int {
	return data1 * data2
}

컬렉션 타입

컬렉션 타입은 여러개의 데이터를 표현하는 방법입니다. Array, List, Set, Map 이 있습니다.

 

Array 는 배열을 의미합니다. Array<Int>, Array<String> 과 같은 형식으로 선언하며 Array(데이터의 개수, { 할당할 수 }) 의 형식으로 할당할 수 있습니다.

배열의 데이터에 접근할 때는 대괄호나 set(), get() 을 이용할 수 있습니다.

fun test() {
	val arr1: Array<Int> = Array(5, { 2 })
    arr1[0] = 10
    arr1.set(1, 20)
    
    println("${arr1.size}")
    println("${arr1[0]}, ${arr1.get(1)}")
}

다만 배열의 데이터가 기초 타입이라면 BooleanArray, ByteArray, CharArray, DoubleArray, FloatArray, IntArray, LongArray, ShrotArray 같은 클래스를 이용해 쉽게 선언할 수도 있습니다.

val arr1: IntArray = IntArray(5, { 3 })

arrayOf() 라는 함수를 사용하면 배열의 선언과 할당을 동시에 할 수 있습니다.

fun test() {
	val arr1 = arrayOf<Int>(10, 20, 30)
}

역시 기초타입을 대상으로 하는 배열이라면 booleanArrayOf(), byteArrayOf() , charArrayOf() , doubleArrayOf() , floatArrayOf() , intArrayOf() , longArrayOf() , shrotArrayOf() 함수도 존재합니다.

val arr1 = intArrayOf(10, 20, 30)

List, Set, Map 은 Collection 인터페이스를 타입으로 표현한 클래스입니다.

 

List 는 순서가 있는 데이터 집합이며 중복을 허용합니다.

Set 은 순서가 없으며 데이터의 중복을 허용하지 않습니다.

Map 은 키와 값으로 이루어져 있으며 키의 중복을 허용하지 않습니다.

 

Collection 타입의 클래스는 가변 / 불변 클래스로 나뉘는데. 불변 클래스는 데이터를 대입하면 더 이상 변경할 수 없는 타입이고, 가변 클래스는 초깃값을 대입한 이후에도 데이터를 추가하거나 변경할 수 있는 타입입니다.

 

List / listOf() / 불변

MutableList / mutableListOf() / 가변

Set/ setOf() / 불변

MutableSet / mutableSetOf() / 가변

Map/ mapOf() / 불변

MutableMap / mutableMapOf() / 가변

 

fun testList() {
	var list = listOf<Int>(10, 20, 30)
    println("${list[0], ${list.get(1)}"}
}

fun testMutableList() {
	var mutableList = mutableListOf<Int>(0, 20, 30)
    mutableList.add(3, 40)
    mutableList.set(0, 10)
}

fun testMap() {
	var map = mapOf<String, String>(Pair("one", "hello"), "two" to "world")
}

fun testMutableList() {
	var mutableMap = mutableMapOf<String, String>("one", "hello")
    mutableMap.put("two", "world")
    mutableMap["three"] = "!"
    
    println(mm.remove("one")
    println(mm.remove("one", "hello"))
}
728x90