프로그래밍 언어/Kotlin (코틀린)

[코틀린 레퍼런스 번역] 시작하기 - 기초 문법

날개 2018. 11. 14. 12:06

[코틀린 레퍼런스 번역] 

시작하기 - 기초 문법 (Basic Syntax)


원문 : Kotlin 공식 사이트 Reference : Getting Started - Basic Syntax

번역 : 날개코더


이글은 코틀린 공식 웹사이트의 레퍼런스를 번역(의역)한 글이며, 원글은 Apache 2 license를 따르고 있습니다.

이 번역글은 자유롭게 링크를 허용합니다. 하지만 그대로 복사하여 자신이 쓴 글인것처럼 블로그나 웹사이트등에 게제 하는 것은 허용하지 않습니다.

내용상 의미가 쉽게 이해되도록 변경한 부분들도 있으며, 의미가 불분명한 부분을 주석을 달아 놓았습니다.

이글을 쓸 당시, 기반이 되는 코틀린의 버전은 1.3입니다. 본 글에서 링크들은 번역된 글이 있으면, 번역된 글로, 아직 번역이 되지 않은 글에는 원문을 링크하였습니다.




패키지 정의


패키지는 소스 파일의 맨 위에 위치해야 합니다 :


package my.demo

import java.util.*

// ...


그렇지만 패키지와 디렉터리(폴더)가 일치해야 하지는 않습니다. 소스 파일들은 파일 시스템 안에서 자유롭게 위치할 수 있습니다.


(역주) 자바에서는 패키지 이름이 디렉터리(폴더) 구조와 동일해야 했고, 파일은 해당 디렉터리(폴더)에 두어야 했습니다. 하지만 코틀린에서는 패키지 이름과 실제 소스 코드 파일이 있는 위치가 동일할 필요가 없습니다. 


패키지 주제 보기 (원문)




함수 정의


아래의 함수는 두개의 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))

}


: 3과 5의 합은 8입니다.


아래의 함수는 표현식 함수 몸체와 추론적 반환형을 가집니다.


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

fun main() {

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

}


: 19와 23의 합은 42입니다.


아래의 함수는 의미 있는 반환 값이 없습니다.


fun printSum(a: Int, b: Int): Unit {

    println("sum of $a and $b is ${a + b}")

}

fun main() {

    printSum(-1, 8)

}


: -1과 8의 합은 7입니다.


Unit 반환형은 생략할 수 있습니다.


fun printSum(a: Int, b: Int) {

    println("sum of $a and $b is ${a + b}")

}


(역주) Unit 형은 자바나 C등의 언어에서의 void 형과 비슷하다고 생각하면 됩니다. 코틀린에서는 함수의 반환형을 함수이름 뒤에 : (콜론)을 붙이고 표시해 줍니다.


함수 주제 보기 (원문)




변수 정의


한번만 값을 할당 할 수 있는 읽기 전용 지역 변수.


    val a: Int = 1  // immediate assignment

    val b = 2   // `Int` type is inferred

    val c: Int  // Type required when no initializer is provided

    c = 3       // deferred assignment


(역주) 변수에 값을 한번만 넣을 수 있습니다. 상수와 비슷하기는 한데, 상수는 변수를 정의할때 할당(초기화)해야 하지만, 코틀린의 val은 위의 예제 코드에서 변수 c와 같이, 변수를 정의할 때 뿐 아니라, 변수만 정의 해 놓고, 추후 값을 할당할 수 있지만, 한번만 할 수 있다는 것이 차이점입니다.


변경할 수 있는 변수.


var x = 5             // `Int` 형으로 자동 추정

x += 1


(역주) var는 다른 언어의 일반적인 변수라고 보면 됩니다. 정의한 후에 자유롭게 값을 변경 할 수 있습니다.


상위 레벨 변수


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


프로퍼티와 필드 보기 (원문)



주석 (comment)


자바와 자바스크립트 처럼, 코틀린은 한줄 주석과 블럭 주석(범위 주석)을 지원합니다.


// This is an end-of-line comment


/* This is a block comment

   on multiple lines. */


하지만 자바와는 달리, 블럭 주석은 또 다른 주석을 포함할 수 있습니다.


문서 주석 문법에 대한 정보는 도큐먼트 코틀린 코드(원문) 에서 볼 수 있습니다.




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


fun main() {

    var a = 1

    // simple name in template:

    val s1 = "a is $a" 


    a = 2

    // arbitrary expression in template:

    val s2 = "${s1.replace("is", "was")}, but now is $a"

    println(s2)

}

결과:


a was 1, but now is 2


문자열 템플릿 보기 (원문)




조건문 사용하기


fun maxOf(a: Int, b: Int): Int {

    if (a > b) {

        return a

    } else {

        return b

    }

}

fun main() {

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

}


결과:


max of 0 and 42 is 42


if 문을 표현으로 사용하기 (표현형 함수):


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


(역주) 함수 정의 부분에서 함수는 표현식으로도 만들수 있고, 반환값은 추론 될 수 있다고 하였습니다. 위의 예 처럼 if 문을 사용할때의 결과가 함수의 반환 값으로 추론이 됩니다. 즉 위의 예시에서는 a 가 더 크면 a 값을, 아니면 b 값을 반환하라는 의미가 됩니다.


if 표현식 보기 (원문)




널가능형(nullable) 값의 사용과 널 확인


참조형은 널(null)값을 가질 수 있다면 반드시 명시적으로 표시를 해야 합니다.


아래는 Int형 변수가 null 값을 반환할 수 있다는 것을 나타냅니다.


fun parseInt(str: String): Int? {

    // ...

}


널값을 반환할 수 있는 함수의 사용 예입니다.


fun parseInt(str: String): Int? {

    return str.toIntOrNull()

}


fun printProduct(arg1: String, arg2: String) {

    val x = parseInt(arg1)

    val y = parseInt(arg2)


    // Using `x * y` yields error because they may hold nulls.

    if (x != null && y != null) {

        // x and y are automatically cast to non-nullable after null check

        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


안전한 널의 사용 (널세이프티 - Null-safety) 보기 (원문)




타입 체크의 사용과 자동 캐스트


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@13221655]' string length is ... err, not a string


클래스형 변환 (Type casts) 보기 (원문)




for 반복문 사용


fun main() {

    val items = listOf("apple", "banana", "kiwifruit")

    for (item in items) {

        println(item)

    }

}

결과:


apple

banana

kiwifruit


또는 (역주: for문에 인덱스를 사용하는 방법)


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


for 반복문 보기 (원문)




while 반복문 사용


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


while 반복문 보기 (원문)




when 문법 사용


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


(역주) when 문법은 자바나 C 등의 언어에서의 switch 문과 비슷한 선택형 문법입니다. 물론 사용법에 있어서는 차이가 많습니다.



when 표현식 보기 (원문)




범위 문법 사용


in 연산자를 사용하여 x 정수값이 범위 안에 있는지 확인합니다.


fun main() {

    val x = 10

    val y = 9

    if (x in 1..y+1) {

        println("fits in range")

    }

}

결과:


fits in range


(역주)


위 예제에서, if 문에는 in 연산자 뒤에 범위 문법이 있습니다. 즉 1..y+1 이라는 범위 표현은 1 부터 y+1 까지 라는 의미 입니다. 


아래는 숫자가 범위를 벗어났는지 확인합니다.


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


반복자를 사용하는 방법 (iterating):


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


범위 (Ranges) 보기 (원문)




컬렉션의 사용


반복자를 통해 컬렉션 탐색: (역주: 여기서의 컬렉션은 listOf)


fun main() {

    val items = listOf("apple", "banana", "kiwifruit")

    for (item in items) {

        println(item)

    }

}

결과:


apple

banana

kiwifruit


컬렉션이 특정한 오브젝트를 포함하고 있는지를 in 연산자를 통해 확인하기: (역주: 여기에서 컬렉션은 setOf)


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


컬렉션에서 람다 표현식을 필터와 맵에 사용하기: 


fun main() {

  val fruits = listOf("banana", "avocado", "apple", "kiwifruit")

  fruits

    .filter { it.startsWith("a") }

    .sortedBy { it }

    .map { it.toUpperCase() }

    .forEach { println(it) }

}

결과:


APPLE

AVOCADO


높은순위(Higher-order) 함수와 람다(Lamdas) 보기 (원문)




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


fun main() {

    val rectangle = Rectangle(5.0, 2.0) //no 'new' keyword required

    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))

    }

}


클래스오브젝트, 인스턴스  보기 (원문)




(C) 2018 WingsNote.com (무단 복제 및 게시 금지, 링크 허용)