Study/kotlin

[코틀린 프로그래밍] Chapter.03 함수를 사용하자

에디개발자 2021. 4. 5. 08:33
반응형

 

나를 닮았다고 한다...

 

함수생성

간단한 함수

코틀린은 KISS ( Keep It Simple Stupid ) 원칙을 준수한다. 단순하게 작성이 가능하다.

fun greet() = "hello"  // 가장 심플한 메소드

 

정적타입의 변수와 마찬가지로 메소드의 리턴타입 또한 타입 추론이 가능하다. 위 코드를 보면 코틀린은 리턴타입이 String 타입이라는 것을 추론할 수 있다.

fun greet() : String = "hello"  // 위 코드와 동일

 

코틀린은 표현식이 많고 명령문은 적다. 아래의 메소드가 표현식이다.

fun sayHello() = println("hello")
코틀린 메소드에서 return 타입은 필수입니다. 위와 같이 리턴타입이 없는 println을 사용할 경우는 Unit 을 리턴합니다. Unit은 아무런 값도 리턴하지 않는 메소드에서 리턴되는 타입입니다.

복잡한 함수

한 줄로 처리되지 않는 복잡한 함수는 자바와 마찬가지로 블록을 작성하고 블록 내에 로직을 작성합니다.

fun max(numbers: IntArray): Int {
    var large = Int.MIN_VALUE
    for ( number in numbers ) {
        large = if (number > large) number else large 
    }
    return large
}

 

 

기본인자와 명시적 인자

Java의 오버로딩과 비슷한 의도로 사용되는 기능입니다. 

Java에서 하나의 메소드가 있다고 가정하고 그 메소드를 여러군데에서 사용 중 입니다.

public Integer sum(int a, int b) {
    // logic..
}

요청사항이 들어와 하나의 파라미터를 추가할 경우 기존의 메소드는 수정하지 않고 메소드명을 동일하게 한 후 파라미터만 추가하여(오버로드) 작성할 수 있습니다.

// 오버로딩
public Integer sum(int a, int b, int c) {
    // logic..
}

 

코틀린은 오버로딩은 지원하지 않지만 명시적 인자를 통해서 위와 비슷한 기능을 구현할 수 있습니다. 

기본인자

일반적으로 메소드에 기본인자로만 구성된 경우입니다.

fun greet(name: String): String = "Hello $name"

 

기본 인자 + 명시적 인자

위 메소드에서 새로운 요청사항이 왔고 새로운 파라미터를 추가할 경우 기본 인자와 명시적 인자를 같이 구성하여 메소드를 수정할 수 있습니다.

fun greet(name: String, msg: String = "Hello"): String = "$msg $name"
fun greet(name: String, msg: String = "Hi ${name.length}") = "$msg $name"
println(greet("Scott", "Howdy"))

println(greet("Scott"))

 

명시적 아규먼트 이용방법

코틀린에서는 아규먼트를 명시하여 순서에 상관없이 개발자가 원하는 아규먼트에 값을 대입할 수 있습니다.

// 명시적 아규먼트를 이용하자!
fun createPerson(name: String, age: Int, height: Int, weight: Int) {
    println("$name $age $height $weight")
}

createPerson("Jake", 12, 152, 43)  // IDE 도움이 없다면 파라미터가 의미하는 바를 알 수 없다.

createPerson(name = "Jake", age = 12, height = 152, weight = 43) // Good!!

createPerson(name = "Jake", 12, weight = 43, height = 152) // Good!!

 

다중인자와 스프레드

여러 개의 인자

Java에서는 '...' 으로 배열( 여러개의 인자 ) 를 받을 수 있습니다.

public int sum(Integer... params) {
    // logic..
}

 

코틀린에서는 이와 비슷한 기능으로 vararg을 사용합니다.

fun varargMax(vararg numbers: Int): Int {
    var large = Int.MIN_VALUE
    for (number in numbers) {
        large = if (number > large) number else large
    }
    return large
}

println(varargMax(1, 5, 2, 5, 12))  // use

 

위에서 학습한 명시적 인자와도 함께 사용할 수 있습니다.

fun greetMany(msg: String, vararg names: String) {
    println("$msg ${names.joinToString(", ")}")
}

greetMany(msg = "Hello", "James", "John", "Tom")  // use

 

스프레드 연산자

vararg 변수를 선언할 경우 배열이나 리스트를 전달할 수 없습니다. 이와 같은 경우에 스프레드 연산자를 사용하여 넘길 수 있습니다.

val values = intArrayOf(1, 52, 11)

println(varargMax(*values))  // 스프레드 연산자

 

구조분해

구조화란 다른 변수의 값으로 객체를 만드는 것이다. 구조분해는 이와 반대로 이미 존재하는 객체에서 값을 추출해 변수로 넣는 작업입니다. 먼저 구조분해를 사용하지 않는 경우를 살펴보겠습니다.

fun getFullName() = Triple("John", "Quncy", "Adams")

// bad!!
val result = getFullName()

val first = result.first
val second = result.second
val third = result.third

println("$first $second $third")

 

Java에서는 위와 같이 하나씩 접근해서 값을 가져와야하는 불편함이 있었습니다. 위 코드는 구조분해를 적용해 수정하겠습니다.

// Good!!
val (s1, s2, s3) = getFullName()
println("$s1 $s2 $s3")

 

모든 변수를 가져오지 않을 수도 있습니다.

// skip!!
val (_, _, s4) = getFullName()

 

정리

- 사용자가 메소드를 만들도록 강요하지 않음
- 애플리케이션이 반드시 객체로만 이루어질 필요가 없고 함수로 구성이 가능하다. 절차적, 객체지향적, 함수형 코드 중 아무거나 선택 가능
- 컴파일러는 단일 표현식이면서 블록이 없는 함수의 경우 리턴타입을 추론 가능. 파라미터를 정의할 땐 항상 타입이 필요
- 기본인자 기능은 함수를 확장하기 쉽게 가능. 함수를 오버로드 하는 일을 줄임
- 'vararg'는 타입의 안정성을 제공하면서 여러 개의 인자를 넘기는 것을 유연하게 제공
- 스프레드 연산자는 vararg 파라미터에 배열을 넘기는 것을 쉽게 제공
- 명시적 인자를 사용하는 것은 코드의 가독성 향상
- 구조분해는 코드의 방해요소를 줄여주고, 코드가 매우 간결

반응형