코틀린

[kotlinlang.org] 한글화. 0 기본 구문

iseohyun 2022. 5. 5.

목차

    원문 : https://kotlinlang.org/docs/basic-syntax.html
    ※ 초보자 시각에서 부적절해 보이는 내용의 순서를 변경하였습니다.

     

    어플리케이션 진입점

    어플리케이션 진입점은 main함수입니다.

    fun main() {
    	println(result)
    }

     

    print는 기본 출력함수입니다.
    println은 기본 출력+줄바꿈입니다.
    fun main() {
        print("Hello ")
        print("world!")
    }
    fun main() {
        println("Hello world!")
        println(42)
    }

     

     

    주석

    한 줄 주석 : // 주석내용
    여러줄 주석 : /* 주석내용 */
    // 한줄 주석입니다.
    
    /* 여러줄
       주석입니다. */

     

     

    변수

    변수 선언은 var 또는 val을 사용합니다. 변수를 문자열과 함께 출력할 땐, $표시를 사용합니다.

    val : value 값 - 고정되어 있음
    var : variable 변수 - 변할 수 있음

    문법은 아래와 같습니다.
    ※ 주석 : 변수명은 전통적으로 소문자를 사용합니다. 변수명 작성 후 띄어쓰기는 하지 않지만 콜론(:) 뒤에는 띄어쓰기 합니다. 타입은 주로 대문자로 시작합니다. 후술하겠지만 타입이란 객체를 의미하며 영문법상 고유명사는 무조건 대문자로 시작합니다. 따라서 타입은 모두 대문자로 작성합니다. 합성어의 경우 띄어쓰기를 하지 않고 대문자를 사용하고, 이름에 특수문자를 사용할 수 없습니다.( Underbar제외(_) )

    val 또는 var 변수명: 타입 = 초기화문구
    1. 이름에 특수문자를 사용할 수 없습니다. (띄어쓰기 안 됨. 특수문자 안됨. Underbar 됨(예외))
    2. 숫자로 시작 할 수 없습니다.
    3. 소문자로 시작합니다. (권고사항)

    예시 : 
    val name: Int
    val typeStyle_1: Object

     

    fun main() {
        val a: Int = 1  // 즉시 할당
        val b = 2   // 정수형 추론
        val c: Int  // 선언
        c = 3       // 할당
        println("a = $a, b = $b, c = $c")
    }
    fun main() {
        var x = 5 // 변수로 설정
        x += 1 // 변경 됨
        println("x = $x")
    }

    선언의 위치는 어디도 될 수 있습니다.

    val a = 1
    fun main() {
        println(a)
        
        val a = 2
        println(a)
    }

     

     

    함수

    함수는 입력과 출력을 갖는 코드블럭입니다. fun으로 시작하고, 함수이름, 입력인자, 출력, 내용을 작성합니다. 입력은 여러개가 될 수 있습니다. 출력은 1개(또는 0개) 만 될 수 있습니다.
    만들어진 함수는 '함수이름(입력)'으로 입력되고, 실행되고 나면 출력으로 대체됩니다.
    괄호를 열면 들여쓰기를 해주세요. 제발

    함수 : function
    입력(인자) : argument
    출력 : retrun
    내용 : statesment or body
    fun 함수명(입력): 출력 {
       내용
    }
    fun sum(a: Int, b: Int): Int {
        return a + b
    }
    
    fun main() {
        print("3 더하기 5 는 ")
        println(sum(3, 5))
    }
    3 더하기 5 는 8

     

     

    함수의 축약

    함수는 축약될 수 있으며, 추론이 가능할 땐 타입을 작성하지 않아도 됩니다.

    fun sum(a: Int, b: Int) = a + b
    
    fun main() {
        println("19 + 23 = ${sum(19, 23)}")
    }
    19 + 23 = 42

     

     

    반환이 없는 함수

    반환자가 없는 경우 Unit을 사용합니다. void → Unit (생략가능)

    fun printSum(a: Int, b: Int): Unit {
        println("$a + $b = ${a + b}")
    }
    
    fun main() {
        printSum(-1, 8)
    }
    fun printSum(a: Int, b: Int){
        println("$a + $b = ${a + b}")
    }
    
    fun main() {
        printSum(-1, 8)
    }

     

     

    Class

    Class는 속성(Properties)과 기능으로 구성되어있습니다. 다음은 속성을 선언하는 방식입니다.
    ※ class는 객체이며 변수와 함수를 각각 속성과 기능이라고 부릅니다.
      C에서는 member variable / member function 이라고 불렀고
      Java에서는 field / method라고 불렀습니다. 차이가 없습니다.

    문법 (선언할 때) :
    class 클래스명(초기화 속성들) {
       일반 속성들
       내용
    }

    문법 (생성할 때) :
    var 변수명: 클래스명(초기화 속성들)

    문법 (접글할 때, 쓸 때)
    변수명.속성 = 저장하고_싶은_것

    문법 (접글할 때, 읽을 때)
    저장할_변수 = 변수명.속성
    class Rectangle(var height: Double, var length: Double) {
        var perimeter = (height + length) * 2 
    }
    fun main() {
        val rectangle = Rectangle(5.0, 2.0)
        println("The perimeter is ${rectangle.perimeter}")
    }
    class 사각형(var 가로: Double, var 세로: Double) {
        var 넓이 = 가로 * 세로 
    }
    
    fun main() {
        val 사각형 = 사각형(5.5, 2.5)
        println(
    """가로가 ${사각형.가로}
    세로가 ${사각형.세로}인
    사각형의 넓이는 ${사각형.넓이} 입니다.""")
    }

     

     

     

    제어문

    조건문

    if

    if문 안에 있는 조건문은 참/거짓이어야 합니다. else이하는 생략이 가능합니다.
    리턴도 생략 가능합니다. 수행문의 가장 마지막 줄을 리턴합니다. ※ (참/거짓)이 아님에 유의

    리턴 = if(조건) { 참:수행문 } else { 거짓:수행문 }
    fun main() {
        val a = 0
        val b = 42
        var c: Int
        
        if (a > b) {
            c = a
        } else {
            c = b
        }
        println("${a}과 ${b}중 큰 수는 ${c}입니다.")
    }
    0과 42중 큰 수는 42입니다.

     

    ※ 한 줄 연산

    1. 수행과정의 결과를 리턴 할 수 있습니다.

    fun main() {
        val a = 0
        val b = 42
        var c: Int
        
        c = if (a > b) {
            a
        } else {
            b
        }
        println("${a}과 ${b}중 큰 수는 ${c}입니다.")
    }

     

    2. 1줄짜리 내용은 괄호{}를 생략 할 수 있습니다.

    fun main() {
        val a = 0
        val b = 42
        var c: Int
    
        // c = if (a > b) { a } else { b }
        c = if (a > b) a else b
        
        println("${a}과 ${b}중 큰 수는 ${c}입니다.")
    }

     

    when

    break가 없어지고, 콤마로 조건을 여러개 넣을 수 있으며, is 타입을 통해서 타입에 해당하는지 선별 할 수 있습니다.
    단, is연산자는 다형성여부를 위한 연산자이므로 A의 상속을 받았다면 is A는 true가 됩니다. [예제2 참조]

    리턴 = when(변수){
        조건1 -> 수행문
        조건2 -> 수행문2
        else -> 아무것도_성립하지_않을_때_수행
    }
    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"))
    }

    [예제2] is A이하 scope{}에서는 객체를 A로 취급합니다.

    open class A()
    class B() : A()
    fun main() {
        var a = A()
        var b = B()
        var inputKeys = listOf('a','A','b','B', a, b)
        for(i in inputKeys) {
            var r = when(i){
            	'A','a' -> "문자 A"
            	'B' -> "B"
                is A -> "Class A" // A와 호환되는지 물어보는 용도이기 때문에
            	else -> "해당없음"
        	}
        	println("${i} = $r")
        }
    }
    a = 문자 A
    A = 문자 A
    b = 해당없음
    B = B
    A@68de145 = Class A
    B@27fa135a = Class A

     

     

    반복문

    for

    어떤 동작을 반복할 때 사용합니다.
    ※ 그룹에 대한 내용은 콜렉션에서 다룹니다.

    for(인덱서 in 그룹) { 바디 }
    fun main() {
        val items = listOf("apple", "banana", "kiwifruit")
        for (item in items) {
            println(item)
        }
    }

    또는

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

    ※ list의 속성에는...
    size, contains(), indexOf()등이 있으며, 아래 문서를 참조합니다.
    https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/list-of.html

    item at 0 is apple
    item at 1 is banana
    item at 2 is kiwifruit

     

     

    while

    while(조건문) { 참일때_바디 }
    do { 참이때_바디 } while(조건문)
    차이점 : do - while은 무조건 1회 실행됨. (최소 1회 보장)
    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

    또는

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

     

     

    범위 표시

    시작_수..끝_수 step 증가수

    예를들어, 3..9 step 2는 [3, 5, 7, 9]를 의미함

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

    응용2

    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

     

     

    범위 감소

    시작_수 downTo 끝_수 step 증가수
    fun main() {
        for (x in 1..10 step 2) {
            print(x)
        }
        println()
        for (x in 9 downTo 0 step 3) {
            print(x)
        }
    }
    13579
    9630

     

     

    컬렉션

    컬렉션은 자료구조에서 열거된 자료형을 관리해주는 클래스를 의미합니다.
    ※ 크게는 자료가 연속된 List와 <키,값>의 쌍 형태로 자료를 관리하는 MAP이 있고, 중복을 인정할 것인지(List)와 중복을 인정하지 않을 것인지(Set)으로 나누어집니다. 자료구조란 입력/삭제/조회/정렬 등 꽤 복잡한 수학적 메커니즘을 사용합니다. 그 만큼 성능체감이 심하다고 할 수 있습니다. 컬렉션을 사용하는 이유는 가장 효율이 좋은 알고리즘을 자동으로 사용할 수 있도록 돕기 때문입니다.

    https://kotlinlang.org/docs/collections-overview.html

    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

     

    Set과 List차이

    Set의 Key는 hash table로 관리되기 때문에 중복값을 허용하지 않습니다.

    fun main() {
        val sets = mutableSetOf("apple", "banana", "kiwifruit")
        val lists = mutableListOf("apple", "banana", "kiwifruit")
        
        println(sets)
        println(lists)
        
        sets.add("apple")
        lists.add("apple")
        
        println(sets)
        println(lists)
    }
    [apple, banana, kiwifruit]
    [apple, banana, kiwifruit]
    [apple, banana, kiwifruit]
    [apple, banana, kiwifruit, apple]

     

     

    람다표현식을 이용한 콜렉션

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

    풀이

    fun main() {
        val fruits = listOf("banana", "avocado", "apple", "kiwifruit")
        var list = fruits.filter { it.startsWith("a") }
        println(list)	// 1
        
        list = list.sortedBy{ it }
        println(list)	// 2
        
        list = list.map { it.uppercase() }
        println(list)	// 3
        
        fruits
            .filter { it.startsWith("a") }
            .sortedBy { it }
            .map { it.uppercase() }
            .forEach { print("$it ") } // 4
    }
    [avocado, apple]
    [apple, avocado]
    [APPLE, AVOCADO]
    APPLE AVOCADO

     

     

    Null

    Null이 될 수 있는 변수는 선언시 타입명뒤에 ?를 붙여줍니다.

    val 변수명: 타입?

    예 :
    val a: Int?
    fun parseInt(str: String) : Int? { }

    ※ Null은 0도 1도 아닌 '없음'을 나타내는 단어입니다. 하지만 실제로 0을 Null로 사용해 왔고, 때문에 생기는 부작용도 많았습니다. 코틀린에서는 null이 들어갈 수 있는 변수를 특별취급합니다.

    아래 예시에서 parseInt는 굉장히 많이 호출되는 범용함수를 간략하게 구현하였습니다. 사용자가 문자를 입력하였을 때, 문자에서 숫자를 추출하는 함수입니다. 간혹 악독한(?) 사용자가 숫자를 입력해달라고 요청을 해도 문자를 입력하는 경우가 있습니다. 이런 경우, 함수가 비정상동작했다는 의미로 null을 반환 할 수 있습니다.
    시나리오에서 숫자 2개가 입력된 6, 7 외에는 나머지 경우에는 null이 반환되었고, 숫자가 아니라고 경고하고 있습니다.

    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("'$arg1' or '$arg2' is not a number")
        }    
    }
    
    fun main() {
        printProduct("6", "7")
        printProduct("a", "7")
        printProduct("a", "b")
    }
    42
    'a' or '7' is not a number
    'a' or 'b' is not a number

     

     

    Null : default value

    만약, 사용하려고 하는 시점에서 Null을 만났다면 default(기본값)을 지정하는 방법은?

    변수?:기본값
    fun main() {
        var a: Int? = null
        val b = 3
        
        //println(a + b) // 에러 발생
        
        println(a?:4 + b)
        
        a = 5
        
        println(a + b) // 에러가 발생하지 않음
    }
    7
    8

     

     

    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 and y are automatically cast to non-nullable after null check
        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'

     

    캐스팅

    is 연산자는 if문을 통해서 타입을 확신 할 수 있는 상태가 되면, 해당 구문에 한하여 타입을 자동 변경할 수 있습니다.

    Any : 어떠한 객체든 될 수 있는 타입
    fun getStringLength(obj: Any): Int? {
        if (obj is String) {
            // if문 안에서만 String으로 간주
            return obj.length
        }
    
        // 이 곳에서 obj의 Type은 Any입니다.
        return null
    }
    
    fun printLength(obj: Any) {
        
        println("'$obj'의 길이는: ${getStringLength(obj) ?: "문자열이 아니잖아!?!?"} ")
    }
    
    fun main() {
        printLength("나랏말싸미 듕귁에 달아")
        printLength(1000)
        printLength(listOf(Any()))
    }
    '나랏말싸미 듕귁에 달아'의 길이는: 12 
    '1000'의 길이는: 문자열이 아니잖아!?!? 
    '[java.lang.Object@41cf53f9]'의 길이는: 문자열이 아니잖아!?!?

     

    만약 if문의 선기술 문장에서 타입을 특정(추론) 할 수 있으면 해당객체로서 사용할 수 있습니다.

    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("Getting the length of '$obj'. Result: ${getStringLength(obj) ?: "Error: The object is not a string"} ")
        }
        printLength("Incomprehensibilities")
        printLength("")
        printLength(1000)
    }
    Getting the length of 'Incomprehensibilities'. Result: 21 
    Getting the length of ''. Result: Error: The object is not a string 
    Getting the length of '1000'. Result: Error: The object is not a string

    댓글