Binary World

기본 구문(Basic Syntax) 본문

개발자의 길/Kotlin

기본 구문(Basic Syntax)

모쿠 2019. 5. 28. 13:45

패키지 정의(Defining packages)

패키지 명시는 가장 위에 줄에 해야한다.

package my.demo

import java.util.*

// ...

 

함수 정의(Defining functions)

Int를 리턴 타입으로 갖는 'Int' 매개 변수 값이 두 개인 함수:

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

fun main() {
    print("sum of 3 and 5 is ")
    println(sum(3, 5))
}

/* 출력 결과 */
sum of 3 and 5 is 8

표현식 본문과 유추된 리턴 타입을 갖는 함수:

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

fun main() {
    println("sum of 19 and 23 is ${sum(19, 23)}")
}

/* 출력 결과 */
sum of 19 and 23 is 42

의미없는 값(void)을 리턴하는 함수:

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

fun main() {
    printSum(-1, 8)
}

/* 출력 결과 */
sum of -1 and 8 is 7

Unit 리턴 타입은 생략이 가능:

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

fun main() {
    printSum(-1, 8)
}

/* 출력 결과 */
sum of -1 and 8 is 7

 

변수 정의(Defining variables)

읽기 전용 지역변수는 val 키워드를 사용해서 정의된다.:

fun main() {
    val a: Int = 1  // 즉시 할당
    val b = 2   // `Int` 타입으로 추론됨
    val c: Int  // 초기화자(initializer)가 없을 때 요구되는 타입이 제공됨
    c = 3       // 후에 할당
    println("a = $a, b = $b, c = $c")
}

/* 출력 결과 */
a = 1, b = 2, c = 3

변수는 var 키워드를 사용해서 정의된다.:

fun main() {
    var x = 5 // `Int` 타입이 추론됨
    x += 1
    println("x = $x")
}

/* 출력 결과 */
x = 6

최상위 변수들

val PI = 3.14 // 전역 읽기 전용 변수
var x = 0 // 전역 변수

fun incrementX() { 
    x += 1 
}

fun main() {
    println("x = $x; PI = $PI")
    incrementX()
    println("incrementX()")
    println("x = $x; PI = $PI")
}

/* 출력 결과 */
x = 0; PI = 3.14
incrementX()
x = 1; PI = 3.14

 

주석(Comments)

자바와 자바 스크립트와 같이 줄의 끝과 블럭 주석을 제공한다.:

// This is an end-of-line comment

/* This is a block comment
   on multiple lines. */

자바와 다르게 중첩될 수 있다.

 

문자열 템플릿 사용(Using string templates)

fun main() {
    var a = 1
    // 템플릿에서 기본 이름
    val s1 = "a is $a" 

    a = 2
    // 템플릿에서 임의의 표현
    val s2 = "${s1.replace("is", "was")}, but now is $a"
    // replace(a, b) : a를 b로 재배치한다.
    println(s2)
}

/* 출력 결과 */
a was 1, but now is 2

조건 표현식 사용(Using conditional expressions)

:

// 기본 표현식
fun maxOf(a: Int, b: Int): Int {
    if (a > b) {
        return a
    } else {
        return b
    }
}

// 간단한 표현식
fun maxOf(a: Int, b: Int) = if (a > b) a else b

fun main() {
    println("max of 0 and 42 is ${maxOf(0, 42)}")
}

/* 출력 결과 */
max of 0 and 42 is 42

 

Null가능한 변수 사용과 Null 체킹(Using nullable values and checking for null)

Null값이 가능할 때 nullable을 명시적으로 표시해야 한다.

null 리턴 표현 함수:

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

nullable 변수 리턴하는 함수 사용:

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

fun printProduct(arg1: String, arg2: String) {
    val x = parseInt(arg1)
    val y = parseInt(arg2)

    // `x * y` 사용은 산출 에러 발생. null로 고정되어 있기 때문에
    if (x != null && y != null) {
        // x, y 는 null 체크 후에 자동적으로 non-nullable로 변경된다.
        println(x * y)
    }
    else {
        println("either '$arg1' or '$arg2' is not a number")
    }    
}


fun main() {
    printProduct("6", "7")
    printProduct("a", "7")
    printProduct("a", "b")
}

/* 출력 결과 */
42
either 'a' or '7' is not a number
either 'a' or 'b' is not a number

위의 방법 또는:

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

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 arg2: '$arg2'")
        return
    }

    // x, y 는 null 체크 후에 자동적으로 non-nullable로 변경된다.
    println(x * y)
}

fun main() {
    printProduct("6", "7")
    printProduct("a", "7")
    printProduct("99", "b")
}

/* 출력 결과 */
42
Wrong number format in arg1: 'a'
Wrong number format in arg2: 'b'

 

타입 체크와 자동 형변환 사용(Using type checks and automatic casts)

is 연산자는 표현식이 인스턴스 타입인지 아닌지 체크한다. 만약 변경 가능한 지역 변수 또는 속성이 특정 타입으로 체크되면, 명시적으로 형변환시킬 필요가 없다.:

fun getStringLength(obj: Any): Int? {
    if (obj is String) {
        // 이 위치에서 `obj` 는 자동으로 'String'으로 형변환된다.
        return obj.length
    }

    // 타입 체크 부분 바깥에서 'obj'는 여전히 'Any' 타입이다.
    return null
}


fun main() {
    fun printLength(obj: Any) {
        println("'$obj' string length is ${getStringLength(obj) ?: "... err, not a string"} ")
    }
    printLength("Incomprehensibilities")
    printLength(1000)
    printLength(listOf(Any()))
}

/* 출력 결과 */
'Incomprehensibilities' string length is 21 
'1000' string length is ... err, not a string 
'[java.lang.Object@3af49f1c]' string length is ... err, not a string 

위 방법 외에:

fun getStringLength(obj: Any): Int? {
    if (obj !is String) return null

    // `obj` is automatically cast to `String` in this branch
    return obj.length
}


fun main() {
    fun printLength(obj: Any) {
        println("'$obj' string length is ${getStringLength(obj) ?: "... err, not a string"} ")
    }
    printLength("Incomprehensibilities")
    printLength(1000)
    printLength(listOf(Any()))
}

/* 출력 결과 */
'Incomprehensibilities' string length is 21 
'1000' string length is ... err, not a string 
'[java.lang.Object@3af49f1c]' string length is ... err, not a string 

또는 :

fun getStringLength(obj: Any): Int? {
    // `obj` is automatically cast to `String` on the right-hand side of `&&`
    if (obj is String && obj.length > 0) {
        return obj.length
    }

    return null
}


fun main() {
    fun printLength(obj: Any) {
        println("'$obj' string length is ${getStringLength(obj) ?: "... err, is empty or not a string at all"} ")
    }
    printLength("Incomprehensibilities")
    printLength("")
    printLength(1000)
}

/* 출력 결과 */
'Incomprehensibilities' string length is 21 
'' string length is ... err, is empty or not a string at all 
'1000' string length is ... err, is empty or not a string at all 

 

For 반복(Loop) 사용(Using a for loop)

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

/* 출력 결과 */
apple
banana
kiwifruit

또는:

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

/* 출력 결과 */
item at 0 is apple
item at 1 is banana
item at 2 is kiwifruit

 

While 반복(Loop) 사용(Using a while loops)

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

/* 출력 결과 */
item at 0 is apple
item at 1 is banana
item at 2 is kiwifruit

 

When 조건식 사용(Using a when expressions)

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

fun main() {
    println(describe(1))
    println(describe("Hello"))
    println(describe(1000L))
    println(describe(2))
    println(describe("other"))
}

/* 출력 결과 */
One
Greeting
Long
Not a string
Unknown

 

범위 사용(Using ranges)

in 연사자를 사용, 숫자가 범위 내에 있는지 확인:

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

/* 출력 결과 */
fits in range

숫자가 범위 밖에 있는지 확인:

fun main() {
    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")
    }
}

/* 출력 결과 */
-1 is out of range
list size is out of valid list indices range, too

범위 내에 반복:

fun main() {
    for (x in 1..5) {
        print(x)
    }
}

/* 출력 결과 */
12345

오름 또는 내림차순으로 특정 값 차이 반복:

fun main() {
    for (x in 1..10 step 2) {
        print(x)
    }
    println()
    for (x in 9 downTo 0 step 3) {
        print(x)
    }
}

/* 출력 결과 */
13579
9630

 

컬렉션(Collections) 사용

컬렉션 내에 반복:

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

/* 출력 결과 */
apple
banana
kiwifruit

in 연산자를 사용해서, 컬렉션이 객체를 포함하고 있는 지 체크:

fun main() {
    val items = setOf("apple", "banana", "kiwifruit")
    when {
        "orange" in items -> println("juicy")
        "apple" in items -> println("apple is fine too")
    }
}

/* 출력 결과 */
apple is fine too

람다 표현식(lambda expressions)을 사용한 필터링과 맵 컬렉션:

fun main() {
  val fruits = listOf("banana", "avocado", "apple", "kiwifruit")
  fruits
    .filter { it.startsWith("a") }
    .sortedBy { it }
    .map { it.toUpperCase() }
    .forEach { println(it) }
}

/* 출력 결과 */
APPLE
AVOCADO

기본 클래스와 인스턴스 생성(Creating basic classes and their instances)

fun main() {
    val rectangle = Rectangle(5.0, 2.0) //'new' 키워드를 사용하지 않음
    val triangle = Triangle(3.0, 4.0, 5.0)
    println("Area of rectangle is ${rectangle.calculateArea()}, its perimeter is ${rectangle.perimeter}")
    println("Area of triangle is ${triangle.calculateArea()}, its perimeter is ${triangle.perimeter}")
}

abstract class Shape(val sides: List<Double>) {
    val perimeter: Double get() = sides.sum()
    abstract fun calculateArea(): Double
}

interface RectangleProperties {
    val isSquare: Boolean
}

class Rectangle(
    var height: Double,
    var length: Double
) : Shape(listOf(height, length, height, length)), RectangleProperties {
    override val isSquare: Boolean get() = length == height
    override fun calculateArea(): Double = height * length
}

class Triangle(
    var sideA: Double,
    var sideB: Double,
    var sideC: Double
) : Shape(listOf(sideA, sideB, sideC)) {
    override fun calculateArea(): Double {
        val s = perimeter / 2
        return Math.sqrt(s * (s - sideA) * (s - sideB) * (s - sideC))
    }
}

/* 출력 결과 */
Area of rectangle is 10.0, its perimeter is 14.0
Area of triangle is 6.0, its perimeter is 12.0

'개발자의 길 > Kotlin' 카테고리의 다른 글

제어 흐름(Control Flow)  (0) 2019.05.28
패키지와 임포트(Packages and Imports)  (0) 2019.05.28
기본 타입(Basic Type)  (0) 2019.05.28
코틀린 개발환경 구축 및 출력  (0) 2019.05.27
Kotlin이란 무엇인가  (0) 2019.05.27
Comments