[Kotlin] 1-1. 기초구문

기초 구문

패키지 정의

패키지 정의는 소스 파일의 처음에 위치해야 한다

pakage my.demo

import java.util.*

디렉토리와 패키지가 일치할 필요는 없으며, 파일 시스템 어디든 소스 파일을 위치시킬 수 있다 ***

함수 정의

두개의 Int 파라미터와 리턴 타입이 Int인 함수

fun sum(a :Int, b: Int) : Int {
    return a + b
}

식 몸체를 사용하고 리턴 타입을 추론

fun sum(a: Int, b: Int) = a + b

의미없는 값을 리턴하는 함수 // Unit == void

fun printSum(a: Int, b: Int) : Unit {
    println("sum of $a and $b is ${a + b}")
}

Unit 리턴 타입은 생략 가능

fun printSum(a: Int, b: Int) {
    println("sum of $a and $b is ${a + b}")
}

로컬 변수 정의

한 번만 할당 가능한(읽기 전용) 로컬 변수

val a : Int = 1  // 즉시 할당
val b = 2  // 'Int' 타입으로 추론
val c: Int  // 초기화를 하지 않으면 타입 필요
c = 3  // 나중에 할당

변경가능 변수

var x = 5  // 'Int' 타입 추론
x += 1

주석

자바나 자바스크립트와 마찬가지로 코틀린은 주석 블록과 줄 수적을 지원

// 이는 줄 주석
/* 이는 여러 줄에 걸친
   주석 블록이다 */

자바와 달리 코틀린은 블록 주석을 중첩할 수 있다


문자열 템플릿 사용

var a = 1
// 템플릿에서 단순 이름 사용
val s1 = "a is $a"

a = 2
// 템플릿에서 임의의 식 사용
val s2 = "${s1.replace("is", "was")}, but now is $a"

조건 식 사용

fun maxOf(a: Int, b: Int) : Int {
    if (a > b)
        return a
    else
        return b
}

if를 식으로 사용하기

fun maxOf(a: Int, b: Int) = if (a > b) a else b

null 가능 값 사용과 null 검사

null 값이 가능할 때 반드시 레퍼런스를 명시적으로 null가능(nullable)로 표시 아래 코드가 str이 정수를 갖지 않으면 null 리턴한다고 할 때

fun parseInt(str: String) : Int? {
    // ...
}

null 가능 값을 리턴하는 함수는 다음과 같이 사용

fun printProduct(arg1: String, arg2: String) {
    val x = parseInt(arg1)
    val y = parseInt(arg2)
    
    // 'x * y' 코드는 에러를 발생하는데, 이유는 null을 가질 수 있기 때문이다
    if(x != null && y != null) {
        // null 검사 이후에 x와 y를 자동으로 null 불가로 변환
        println(x * y)
    }
    else {
        println("either '$arg1' or '$arg2' is not a number")
    }
}

또는

fun printProduct(arg1: String, arg2: String) {
    val x = parseInt(arg1)
    val y = parseInt(arg2)
    
    if(x == null) {
        println("Wrong number format in arg1: '$arg1'")
        return
    }
    if(y == null) {
        println("Wrong number format in arg1: '$arg2'")
        return
    }
    
    // null 검사 이후에 x와 y를 자동으로 null 불가로 변환
    println(x * y)
}

타입 검사와 자동 변환 사용

is 연산자는 식이 타입의 인스턴스인지 검사 / 불변 로컬 변수나 프로퍼티가 특정 타입인지 검사할 경우 명시적으로 타입을 변환할 필요 없음

fun getStringLength(obj: Any): Int? {
    if(obj is String)
        //이 블록에서는 'obj'를 자동으로 'String'으로 변환
        return obj.length
    // 타입 검사 블록 밖에서 'obj'는 여전히 'Any' 타입
    return null

또는

fun getStringLength(obj: Any): Int?	{				
    if(obj !is String) return null
	
    // 'obj'를 자동으로 'String'으로 변환
    return obj.length
}

또는 심지어 다음도 가능

fun getStringLength(obj: Any): Int? {
    // 우변의 '&&'에서 'obj'를 자동으로 'String'으로 변환
    if(obj is String && obj.length > 0)
        return obj.length
    return null
}

for 루프 사용

val items = listOf("apple", "banana", "kiwi")
for(item in items) {
    println(item)
}

또는

val items = listOf("apple", "banana", "kiwi")
for(index in items.indices) {
    println("item at $index is ${items[index]}")
}

while 루프 사용

val items = listOf("apple", "banana", "kiwi")
var index = 0
while(index < items.size) {
    println("item at $index is ${items[index]})
    index++
}

when 식 사용

fun describe(obj: Any): String =
    when(obj) {
        1 -> "one"
        "Hello" -> "Greeting"
        is Long -> "Long Type"
        !is String -> "Not a string"
        else -> "Unknown"
    }

범위 사용

in 연산자를 사용해서 숫자가 범위에 들어오는지 검사

val x = 10
val y = 9
if(x in 1..y+1)
    println("fits in range")

!in 연산자를 사용해서 숫자가 범위를 벗어나는지 검사

val list = listOf("a", "b", "c")
if(-1 !in 0..list.lastIndex)
    println("-1 is out of range")
if(list.size !in list.indices) 
    println("list size is out of valid list indices range too")

범위를 반복

for(x in 1..5)
    print(x)

또는 단순한 범위 이상

for(x in 1..10 step 2)
    print(x)
for(x in 9 downTo 0 step 3)
    print(x)

콜렉션 사용

콜렉션에 대한 반복

for(item in items) {
    print(item)
}

in 연산자로 콜렉션이 객체를 포함하는지 검사

when {
    "Orange" in items -> println("juicy")
    "apple" in items -> println("apple is fine too")
}

콜렉션을 걸러내고 변환하기 위해 람다 식 사용

fruits
    .filter {it.startsWith("a")}
    .sortedBy{it}
    .map{it.toUpperCase()}
    .forEach{println(it)}

기본 클래스와 인스턴스 만들기

val rectangle = Rectangle(5.0, 2.0)  // 'new' 키워드 필요 없음
val triangle = Triangle(3.0, 4.0, 5.0)