본문 바로가기

Language/Kotlin

코틀린[Kotlin] 기본 문법 1 (함수, 변수, 널 안전성)

아래 코틀린 코드는 play.kotlinlang.org에서 실행할 수 있습니다.

코틀린 공식 문서를 참고해 작성되었습다.

 

 

Hello world

package org.example.ki         // 1

fun main() {                        // 2
    println("Hello, World!")        // 3
}
  1. Kotlin 코드는 일반적으로 패키지에 정의됩니다. 패키지를 명시하는 것은 선택 사항입니다. 소스 파일에 패키지를 지정하지 않으면 해당 내용이 기본(default) 패키지로 이동합니다.
  2. Kotlin 애플리케이션의 진입점은 메인 함수입니다. Kotlin 1.3부터 ​​매개변수 없이 main을 선언할 수 있습니다.
  3. println은 표준 출력에 한 줄을 씁니다. println은 암시적으로 import됩니다. 또한 세미콜론을 표기하는 것은 선택 사항입니다.

Kotlin 1.3 이전 버전에서는 기본 함수에 Array<String> 유형의 매개변수가 있어야 합니다

fun main(args: Array<String>) {
    println("Hello, World!")
}

 

함수 (Functions)

Kotlin 함수는 fun 키워드를 사용하여 선언됩니다.

Default Parameter와 Named Arguments

  • Default Parameter
    • 함수 매개변수는 기본값을 가질 수 있고, 해당 인자를 전달하지 않고 함수를 호출할 때 사용됩니다.
  • Named Arguments
    • 함수를 호출할 때 하나 이상의 인자에 이름을 지정할 수 있습니다. 이는 함수에 인자가 많고 값을 인자와 연결하기 어려운 경우, 특히 boolean 또는 null 값인 경우에 유용할 수 있습니다.

 

fun printMessage(message: String): Unit {                               // 1
    println(message)
}

fun printMessageWithPrefix(message: String, prefix: String = "Info") {  // 2
    println("[$prefix] $message")
}

fun sum(x: Int, y: Int): Int {                                          // 3
    return x + y
}

fun multiply(x: Int, y: Int) = x * y                                    // 4

fun main() {
    printMessage("Hello")                                               // 5                    
    printMessageWithPrefix("Hello", "Log")                              // 6
    printMessageWithPrefix("Hello")                                     // 7
    printMessageWithPrefix(prefix = "Log", message = "Hello")           // 8
    println(sum(1, 2))                                                  // 9
    println(multiply(2, 4))                                             // 10
}
  1. String 유형의 파라미터를 사용하고 Unit을 반환하는 간단한 함수(즉, 반환 값 없음)
  2. 기본값 "Info"와 함께 두 번째 선택적 매개변수를 취하는 함수입니다. 반환 유형은 생략되어 실제로 Unit임을 의미합니다.
  3. 정수를 반환하는 함수입니다.
  4. 정수(추론됨)를 반환하는 단일 표현식 함수입니다.
  5. Hello 인수를 사용하여 첫 번째 함수를 호출합니다.
  6. 두 개의 파라미터를 사용하여 함수를 호출하고 둘 다에 대한 값을 전달합니다.
  7. 두 번째 파라미터를 생략하고 동일한 함수를 호출합니다. 두 번째 파라미터에는 기본값 "Info"가 사용됩니다.
  8. Named Arguments를 사용하고 인자의 순서를 변경하여 동일한 함수를 호출합니다.
  9. 더하기 함수의 반환 값을 출력합니다.
  10. 곱하기 함수의 반환 값을 출력합니다.

Default Parameter 뒤의 마지막 인자가 람다인 경우 Named Arguments로 전달하거나 괄호 외부에 전달할 수 있습니다

fun foo(
    bar: Int = 0,
    baz: Int = 1,
    qux: () -> Unit,
) { /*...*/ }

foo(1) { println("hello") }     // 기본값 baz = 1 사용
foo(qux = { println("hello") }) // 기본값 bar = 0 and baz = 1 사용
foo { println("hello") }        // 기본값 values bar = 0 and baz = 1 사용

 

Infix 함수

infix 키워드로 표시된 함수는 infix 표기법을 사용하여 호출할 수도 있습니다(함수 호출을 위한 점과 괄호 생략하는 것)

Infix 함수는 다음 요구 사항을 충족해야 합니다.

  • 멤버 함수 또는 확장 함수여야 합니다.
  • 단 하나의 매개변수를 가져야 합니다.
  • 매개변수는 가변 개수의 인수(varargs)를 허용하지 않아야 하며 기본값이 없어야 합니다.
    infix fun Int.shl(x: Int): Int { ... }
    
    // calling the function using the infix notation
    1 shl 2
    
    // is the same as
    1.shl(2)​

Operator 함수

특정 함수는 Operator에게 "업그레이드"되어 해당 Operator 기호로 호출할 수 있습니다.

operator fun Int.times(str: String) = str.repeat(this)       // 1
println(2 * "Bye ")                                          // 2
// Bye Bye 

operator fun String.get(range: IntRange) = substring(range)  // 3
val str = "Always forgive your enemies; nothing annoys them so much."
println(str[0..14])
// Always forgive
  1. 이것은 Operator modifier를 사용하여 한 단계 위에서 infix 함수를 사용합니다.
  2. times()의 연산자 기호는 *이므로 2 * "Bye"를 사용하여 함수를 호출할 수 있습니다.
  3. 연산자 함수는 문자열에 대한 범위 접근을 허용합니다.

 

vararg 매개변수가 있는 함수

Varargs를 사용하면 인자를 쉼표로 구분하여 원하는 수만큼 전달할 수 있습니다.

fun printAll(vararg messages: String) {                            // 1
    for (m in messages) println(m)
}
printAll("Hello", "Hallo", "Salut", "Hola", "你好")                 // 2

fun printAllWithPrefix(vararg messages: String, prefix: String) {  // 3
    for (m in messages) println(prefix + m)
}
printAllWithPrefix(
    "Hello", "Hallo", "Salut", "Hola", "你好",
    prefix = "Greeting: "                                          // 4
)

fun log(vararg entries: String) {
    printAll(*entries)                                             // 5
}
  1. vararg 수정자는 매개변수를 vararg로 바꿉니다.
  2. 이렇게 하면 임의의 수의 문자열 인수로 printAll을 호출할 수 있습니다.
  3. 명명된 매개변수 덕분에 vararg 뒤에 같은 유형의 다른 매개변수를 추가할 수도 있습니다. 값을 전달할 방법이 없기 때문에 Java에서는 허용되지 않습니다.
  4. named parameters를 사용하여 vararg와 별도로 접두사에 값을 설정할 수 있습니다.
  5. 런타임에 vararg는 배열일 뿐입니다. vararg 매개변수에 전달하려면 항목(Array<String>) 대신 *항목(String의 vararg)을 전달할 수 있는 특수 스프레드 연산자 *를 사용하면 됩니다.

 

변수 (Variables)

코틀린은 타입 추론이 가능합니다. 변수의 유형을 명시적으로 선언할 수 있지만 일반적으로 컴파일러가 이를 유추하여 작업을 합니다. Kotlin은 불변성을 적용하지 않지만 권장됩니다. var보다 val을 사용하는게 권고됩니다.

var a: String = "initial"  // 1
println(a)
val b: Int = 1             // 2
val c = 3                  // 3
  1. 가변 변수를 선언하고 초기화합니다.
  2. 불변 변수를 선언하고 초기화합니다.
  3. 불변 변수를 선언하고 유형을 지정하지 않고 초기화합니다. 컴파일러는 Int 유형을 유추합니다.
var e: Int  // 1
println(e)  // 2
// Variable 'e' must be initialized
  1. 초기화하지 않고 변수를 선언합니다.
  2. 변수를 사용하려고 하면 컴파일러 오류가 발생합니다. Variable 'e' must be initialized.

 

변수를 초기화할 때를 자유롭게 선택할 수 있지만 첫 번째 읽기 전에 초기화해야 합니다.

val d: Int  // 1

if (someCondition()) {
    d = 1   // 2
} else {
    d = 2   // 2
}

println(d) // 3
  1. 초기화하지 않고 변수를 선언합니다.
  2. 어떤 조건에 따라 다른 값으로 변수를 초기화합니다.
  3. 변수는 이미 초기화되었기 때문에 읽을 수 있습니다.

 

널 안전성 (Null Safety)

NullPointerException를 없애기 위한 노력으로 Kotlin의 변수 타입은 null 할당을 허용하지 않습니다. null일 수 있는 변수가 필요한 경우 ?를 타입의 끝에 추가하여 nullable로 선언합니다.

var neverNull: String = "This can't be null"            // 1

neverNull = null                                        // 2

var nullable: String? = "You can keep a null here"      // 3

nullable = null                                         // 4

var inferredNonNull = "The compiler assumes non-null"   // 5

inferredNonNull = null                                  // 6

fun strLength(notNull: String): Int {                   // 7
    return notNull.length
}

strLength(neverNull)                                    // 8
strLength(nullable)                                     // 9
  1. null이 아닌 String 변수를 선언합니다.
  2. null을 허용하지 않는 변수에 null을 할당하려고 하면 컴파일 오류가 발생합니다.
  3. nullable String 변수를 선언합니다.
  4. null 값을 nullable 변수로 설정해도 에러가 발생하지 않습니다.
  5. 타입을 추론할 때 컴파일러는 값으로 초기화된 변수에 대해 null이 아닌 것으로 가정합니다.
  6. 타입이 추론된 변수에 null을 할당하려고 하면 컴파일 오류가 생성됩니다.
  7. null이 아닌 문자열 매개변수를 사용하여 함수를 선언합니다.
  8. String(nullable이 아님) 인수를 사용하여 함수를 호출합니다.
  9.  (nullable) 인자인 String?으로 함수를 호출할 때, 컴파일 오류가 생성됩니다.

 

Null을 가지고 작업하기

때때로 Kotlin 프로그램은 외부 Java 코드와 상호 작용하거나 실제로 부재 상태를 나타내는 경우와 같이 null 값으로 작업해야 합니다. Kotlin은 이러한 상황을 우아하게 처리하기 위해 null 추적을 제공합니다.

fun describeString(maybeString: String?): String {              // 1
    if (maybeString != null && maybeString.length > 0) {        // 2
        return "String of length ${maybeString.length}"
    } else {
        return "Empty or null string"                           // 3
    }
}
  1. nullable 문자열을 받아 설명을 반환하는 함수입니다.
  2. 주어진 문자열이 null이 아니고 비어 있지 않으면 길이에 대한 정보를 반환합니다.
  3. 그렇지 않으면 호출자에게 문자열이 비어 있거나 null임을 알립니다.