ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [코틀린 완벽 가이드] 3장 함수 정의하기 (3.1 함수)
    코틀린 공부/코틀린 2023. 12. 28. 10:32

    여기서는 함수의 기본적인 내부 구조를 살펴보고 인자(named argument), 디폴트(default) 값, vararg 스타일 함수 등을 살펴본다. 그리고 코틀린 언어의 명령형(imperative) 제어 구조도 다룬다. 

     

    배우는 내용 :

    • 코틀린 함수의 구조
    • 제어 구조 : 조건문, 루프, 오류 처리

     

    3.1 함수 

    3.1.1 코틀린 함수의 구조

    반지름이 주어졌을 때 원의 넓이를 계산하는 함수를 정의

    fun circleArea(radius: Double) : Double{
        return PI*radius*radius
    }
    
    fun main() {
        println(circleArea(3.0)) // 28.274333882308138
    }
    
    
    fun 함수 이름(함수에서 사용할 파라미터) : return 값{
        함수가 할 내용
    }

     

     

    자바 메서드 파라미터는 디폴트가 가변이므로 함수 내부에서 변경하지 못하게 하려면 final을 지정해 불변 값으로 바꿔야 했다. 하지만 코틀린 함수의 파라미터는 무조건 불변이다.

    fun increment(a: Int): Int{
        return a++ // Val cannot be reassigned
    }
    

     

    그리고 파라미터 압에 val이나 var를 표시할 수 없다는 점에 유의하라. 이렇게 강제하는 이유는 파라미터에 대입하는 중에 실수할 가능성이 높을 뿐아니라 파라미터를 불변 값으로 강제하는 편이 더 깔끔하고 이해하기 편한 코드를 만들어내기 때문이다. 

     

    코틀린 함수는 return 값을 지정해야한다. 지정되어 있지 않다면 Unit이 생략되어 있다는 의미다. (자바의 void랑 같다.)

     

    call-by-value

    코틀린은 값에 의한 호출 의미론을 사용한다. 이 말은 파라미터 값에 호출하는 쪽의 인자를 복사한다는 뜻이다. 특히 호출 인자를 전달한 변수를 변경해도 호출된 함수 내부의 파라미터 값에는 영향이 없다는 뜻이다. 하지만 파라미터가 참조라면 호출한 쪽의 데이터는 그대로 남아있고 이 데이터에 대한 참조만 복사된다. 따라서 파라미터 자체는 함수 내부에서 바뀔 쉬 없지만, 일반적으로 파라미터가 가르키는 데이터는 바뀔 수 있다.  

     

    즉 배열 같이 참조하는 데이터를 넘겨주면 함수 내부에서 변경이 외부까지 적용되지만, Int 같은 값을 나타내는 파라미터는 함수 내부에서 변경해도 외부에서는 안바뀐다는 것이다.

     

    Call by Reference 개념 찾아보기

     

     

    식이 본문 (experssion-body)인 함수

    어떤 함수가 단일 식으로만 구현될 수 있다면 return 키워드와 블록을 만드는 중괄호({})를 생략하고 다음과 같은 형태로 함수를 작성해도 된다. (반환 타입 생략 가능)

    fun circleArea(radius: Double) : Double  =  PI * radius * radius
    fun circleArea2(radius: Double)  =  PI * radius * radius

     

    식이 본문인 함수는 간단하지만 조심스럽게 사용해야 한다. 복잡하게 표현된 식이 본문인 함수는 블록구문을 사용해 가독성을 높여주는 편이 더 낫다. (return을 추가하면 컴파일 오류 발생!!!)

    fun circleArea3(radius: Double)  =  { PI * radius * radius }

     

    3.1.2 위치 기반 인자와 이름 붙은 인자

    기본적으로 함수 호출 인자는 순서대로 파라미터에 전달된다. 이런 방식을 위치 기만 인자(positional argument)라고 한다.

    fun rectangleArea(width: Double, height: Double): Double {
        return width * height
    }
    println("Rectangle area: ${rectangleArea(10.0,10.0)}") // Rectangle area: 100.0

     

    코틀린은 이름 붙은 인자(named argument)라고 불리는 방식도 제공한다.

    rectangleArea(width = 10.0, height = 11.0)
    rectangleArea(height = 10.0, width = 11.0)

     

     

    코틀린 1.4 이전에는 이름 붙은 인자를 쓰기 시작하면 그 이후의 모든 인자에 이름을 붙여야 했다. 1.4부터는 이름 붙은 인자를 중간에 섞어 쓸 수도 있다. (아래는 원본 문자열의 내용은 바뀌지 않는다.)

    fun swap(s: String, from:Int, to:Int): String{
        val chars = s.toCharArray()
        //배열 원소 교환하기
        val tmp = chars[from]
        chars[from] = chars[to]
        chars[to] = tmp
        return chars.concatToString()
    }
    println(swap("Hello", from=1, to=3)) // Hlleo
    

     

    3.1.3 오버로딩과 디폴트 값

    자바 메서드와 마찬가지로 코틀린 함수도 오버로딩을 할 수 있다. 즉, 이름이 같은 함수(parameter가 다른)를 여럿 작성할 수 있다.

    fun readInt() = readln().toInt()
    fun readInt(radix: Int) = readln().toInt(radix)

     

     

    코틀린에서는 경우에 따라 함수 오버로딩을 쓰지 않아도 된다. 더 우아한 해법인 디폴트 파라미터가 있기 때문이다. 파라미터 뒤에 변수 초기화식을 추가하면 원하는 파라미터에 디폴트 값을 제공할 수 있다.

    fun readInt(radix: Int = 10) = readLine()!!.toInt(radix)
    
    val decimalInt = readInt()
    val decimalInt2 = readInt(10)

     

    3.1.4 vararg

    fun printSorted(vararg items: Int){
        items.sort()
        println(items.contentToString())
    }
    printSorted(6,2,10,1) // [1, 2, 6, 10]

     

    스프레드(spread) 연산자인 *를 사용하면 배열을 가변 인자 대신 넘길 수 있다.

    val numbers = intArrayOf(6,2,10,1)
    printSorted(*numbers)

     

    하지만 이때 얕은 복사가 이뤄진다. 즉, 배열 내부에 참조가 들어가 있는 경우에는 참조가 복사되기 때문에 참조가 가르키는 데이터가 호출하는 쪽과 함수 내부 배열에서 공유된다.

     

    printSorted(6, 1, *intArrayOf(3, 8), 2) //6, 1, 3, 8, 2 순서로 배열이 전달

     

    둘 이상의 vararg 파라미터로 선언은 금지. 그러나 vararg 파라미터에 콤마로 분리한 여러 인자와 스프레드를 섞어 전달하는건 가능

     

    3.1.5 함수의 영역과 가시성

    코틀린 함수는 정의된 위치에 따라 세가지로 구분할 수 있다.

    • 파일에 직접 선언된 최상위 함수
    • 어떤 타입 내부에 선언된 맴버 함수
    • 다른 함수 안에 선언된 지역 함수

    main()과 같은 최상위 함수는 public 함수다. 즉, 프로젝트 어디에서나 쓰일 수 있다.

     

    최상위 함수 정의 앞에 privateinternal 이라는 키워드를 붙일 수 있다. 이런 키워드를 가시성 변경자(visibility modifier)라고 부른다.

     

    private으로 함수를 정의하면 함수가 정의된 파일 안에서만 해당 함수를 사용할 수 있다.

    internal 변경자는 함수가 적용된 모듈 내부에서만 함수 의 사용이 가능

    public은 디폴트로 따로 적어주지 않는다면 public이기 때문에 생략

     

    3.2 패키지와 임포트 

    생략...

     

    3.3 조건문

    3.3.1 if 문으로 선택하기

    (자바랑 비슷해서 일부 생략)

     

    자바와 코틀린의 차이점은 if를 식으로 사용할 수 있다는 것이다.

    fun max(a: Int, b: Int) = if(a > b) a else b

     

    한쪽만 블록이 있을 수도 있다. 단, if else 둘다 있어야 한다.

    val result = if(i > 0){
        println("i is bigger than 0")
    }else
        println("i is smaller than 0")

     

    코틀린은 자바가 가지고 있는 3항 연산자 (조건 ? A : B) 가 없다. 이 부분이 그것을 상쇄해준다.

     

    3.3.2 범위, 진행, 연산

    코틀린은 순서가 정해진 값 사이의 수열(interval)을 표현하는 몇가지 타입을 제공한다. 코틀린에서는 이런 타입을 범위(range)라고 부름

     

    범위를 만드는 가장 간단한 방법은 .. 연산자를 사용하는 것이다.

    val chars = 'a'..'z'
    val twoDigits = 10.. 99

     

     

Designed by Tistory.