Android/Kotlin

[book][공부중] 코틀린 완벽 가이드 "3장 함수 정의하기"

네모메모 2022. 6. 14. 01:12
반응형

아래 책 공부하며 '새롭게 배운 점', '더 궁금해진 것', '자주 까먹는 부분'들에 대한 포스팅입니다.

 

 

코틀린 완벽 가이드 입문부터 활용까지, 필요한 지식 총망라!

저자 알렉세이 세두노프|역자 오현석|길벗 |2022.02.28
원제Kotlin in-depth : a comprehensive guide to modern multi-paradigm language. 1-2

페이지 704|ISBN  9791165218911|판형 규격외 변형


 

"3장 함수 정의하기"

 


1. 파라미터

- 파라미터 앞에 var 나 val 사용불가

- 반드시 타입 지정해야함

- 함수 호출 시 인자값으로 초기화되는 불변 지역변수

- 파라미터가 참조타입(Call by Ref)인 경우 파라미터는 변경 불가하나 참조타입 파라미터가 가진 데이터는 변경 가능

 

- '위치 기반 인자'와 '이름 붙은 인자'를 함께 사용 시 '이름 붙은 인자'를 위치에 맞게 기재해야함

fun A (a: Int, b: Int, c: Int)

A(1,2,3)

A(1, b=2, 3)

A(b=2, a=1, c=3)

A(b=2, a=1, 3) // error

A(b=2, 1, 3) // error

 

 


2. 리턴 타입 생략가능 케이스 2가지 

 #1) Unit 타입을 반환하는 경우, 

 

 #2) 식(expression)이 함수본문인 함수

     - (expression)이 함수본문이자 리턴값

     - 리턴문과 괄호{}를 생략한다.

     - 단일 식만으로 구현가능한 함수

fun 함수명(파라미터 ..) =  
 -  '='을 사용하여 함수 표현됨
 -  return문 사용불가(error)
 -  {}블록은 식이 아닌 익명함수가 리턴되므로 사용주의
        ㄴ> '#2)식이 함수본문이자 리턴값인 함수'가 리턴값인 함수
        ㄴ> {}블록이 익명함수를 기술한 람다로 해석되므로

        ㄴ> fun 함수명(파라미터 ..) = { 함수본문인 식 }       

- cf) 보통 함수 

fun 함수명(파라미터 ..): 리턴타입 {
           함수본문
           return 리턴값
}

 


3. 오버로딩

- 함수의 파라미터 타입 또는 갯수가 다른 오버로딩 가능

- 함수의 리턴타입만 다른 오버로딩 불가능

- 여러 오버로딩 함수 중 어느함수를 호출해야할지는 컴파일러가 자바 'Overloading resolution(오버로딩 해소 규칙)'에 따라 결정한다.

'Overloading resolution(오버로딩 해소 규칙)'
    1. 파라미터 개수와 타입 기준을 만족하는 함수 검색
    2. 1번에서 검색된 오버로딩 함수들 중 파라미터 타입이 더 상위인 함수를 '덜 구체적인 함수'로 제외시킨다.
        ㄴ> 2-1. 디폴트 파라미터 있는 함수도 덜 구체적인 함수로 제외함
        ㄴ> 2-2.  vararg 파라미터 있는 함수도 덜 구체적인 함수로 제외함
    3. 2번 과정을 반복하여 1개의 함수만 남으면 해당 함수 호출하고, 2개이상이 남는 경우 컴파일 오류 발생
ex) A(1,2)를 호출 시 1,2,3번이 검색(위1번)됨 -> '덜 구체적인 함수'로 상위타입 파라미터를 가진 2,3번 제외(위2번) -> 1번 호출
          fun A(a: Int, b:Int)  //  A(1, 2)를 호출 시
          fun A(a: Int, b:Long) //  A(1, 2L)를 호출 시
          fun A(a: Any, b:Int)    // A(1L, 2)를 호출 시
          fun A(a: Int, b:Int, c: Int)

+) 상위타입 오버로딩 함수(='덜 구체적인 함수' )호출하고 싶을 때는 as 키워드 (=캐스팅연산자)를 사용
    ㄴ> ex) A(1, 2 as Long) //  fun A(a: Int, b:Long)를 호출함

오버로딩보다 더 우아한 해법

4. '디폴트 파라미터'

- 함수 호출 시에는 디폴트 파라미터 여부와 상관없이 이름없으면 무조건 순서대로 매칭시킨다. 

  ㄴ> 함수 선언에 '디폴트 파라미터' 뒤에 일반 파라미터 있으면, 디폴트값 사용 시 일반 파라미터는 항상 이름 붙여서 호출해야 한다.

- 함수 선언 시 일반 파라미터 모두 기재 후 뒤에 '디폴트 파라미터' 기재하는 것이 좋다.

fun A(a: Int, b:Int , c: Int=30) {}
A(10, 20)

fun A1(a: Int, b:Int=20, c: Int){}
A1(10, 20) // error (c 미입력)
A1(a=10, c=20)

fun A2(a: Int = 10, b:Int = 20, c: Int){}
A2(c=30)
A2(30) // error (b, c 미입력)

A2(30, 10) // error (c 미입력)
A2(a=40, 30) // error (c 미입력)
A2(b=40, 30) // error (c 미입력)
A2(1, c=30)

A2(10, b=40, 30)
        
fun A3(a: Int=10, b:Int , c: Int=30){}
A3(10, 20)

 


 

 

5.가변인자  vararg

- 파라미터 갯수가 가변적으로 정할 수 있도록 설정

 

fun 함수명(vararg 파라미터명: 파라미터타입): 리턴타입 {
           ...
}

- 1번만 선언 가능

- vararg 파라미터는 이름 붙여서 호출할 수 없다.

 

- vararg 함수 내부에서 적절한 "배열 타입"으로 처리됨

fun A1(vararg item: Int) //  item은 내부에서 Int를 원소로 가지는 배열 타입인 IntArray로 취급됨

fun A2(vararg item: IntArray) //  item은 내부에서 IntArray를 원소로 가지는 배열로 취급됨

 

 

- 배열을 vararg 로 넘길 때, 스트레드 연산자 *를 사용 (배열을 꺼내준다는 의미로 이해)

fun A2(vararg item: IntArray) 
val arr = intArrayOf(1,2,3)

A2(*arr)
A2(5, *arr, 1, 2) // [5, 1, 2, 3, 1, 2] 합쳐진 단일 배열로 전달
A2(arr) // error

ㄴ> 스프레드 연산자와 여러 인자를 함께 vararg 로 전달  단일 배열로 합쳐져 함수에서 처리된다.

ㄴ>  스프레드 연산자 사용 얕은복사가 이루어져 참조값으로 전달되어 함수 밖 원본대상에도 영향을 준다.

 

 

- 일반 파라미터와 사용 시,

ㄴ> vararg 뒤에 일반파라미터 존재 시 : 일반파라미터에 이름 명시해야함
ㄴ> 일반파라미터  뒤에 vararg 존재 시 : 첫번째 값은 무조건 일반파라미터로 인식됨 

    => 일반 파라미터 모두 기재 후 뒤에 'vararg 파라미터' 기재하는 것이 좋다.

// vararg 뒤에 일반파라미터 존재 시
fun A0(vararg a: Int, b: String){}
A0(1,2,3, "10") // error (Type mismatch. Required:Int / Found:String )

// vararg 앞에 일반파라미터 존재 시
fun A00(b: Int, vararg a: Int){}
A00(10,1,2,3) // b에는 10이, a에는 [1,2,3]이 전달됨

 

- 디폴트 파라미터와 사용 시 

ㄴ> vararg 뒤에 디폴트파라미터 존재 시 : 디폴트파라미터에 이름 명시해야함
ㄴ>  vararg 앞에 디폴트파라미터 존재 시 : 첫번째 값은 무조건 디폴트파라미터로 인식되고, vararg 전달 인자를 이름붙은인자와 스프레드연산자를 사용해 전달해야한다.(비효율적)

// vararg 뒤에 디폴트파라미터 존재 시 
fun A1(vararg a: Int, b: Int = 100){}
A1(1,2,3, b=10)
fun A11(vararg a: Int, b: String = "100"){}
A11(1,2,3, "b") // error (Type mismatch.Required:Int / Found:String)

// vararg 앞에 디폴트파라미터 존재 시 
fun A2(b: Int = 100, vararg a: Int){}
val arr = intArrayOf(1,2,3, 5)
A2(1,2,3, 5)
A2(a = *arr)
A2(*arr) // error (Type mismatch.Required:Int / Found:IntArray)

 


6. 정의된 위치에 따른 코틀린의 함수 종류


6-1. 최상위 함수 : (클래스 밖인) 파일에 직접 선언된 함수

- cf) 자바의 함수는 모두 클래스에 들어있어야 한다.

 

6-2. 멤버 함수 : (클래스 등의) 어떤 타입 내부에 선언된 함수


6-3. 지역 함수 : 다른 함수 안에 선언된 함수

- 자신을 둘러싼 함수 내의 매개변수, 지역변수, 다른 지역 함수에 접근 가능

-  ex) main함수 

- cf) 자바의 함수는 모두 클래스에 들어있어야 한다.

더보기

Q. 자바의 함수는 모두 클래스에 들어있어야 한다면 그렇지 않은 코틀린의 최상위함수, 지역함수는들은 JVM에서 어떻게 컴파일 가능한가?

ㄴ> Re: 지역함수도 이와 비슷한 트릭으로 JVM에서 정의하며 지역함수 접근 가능 영역(상위 함수 내 모든 변수,함수)도 하나의 특별한 클래스로 선언하여 접근 가능 => 지역함수 호출 시 비용이 든다.

 

 

 


최상위 main() 함수

- 코틀린 파일마다 자동으로 만들어지는 특별한 파사드 클래스의 정적 멤버

 


7. 접근제한자

- 접근제한자 디폴트값은 'public'

- internal은 같은 모듈 내 접근 가능


8. 패키지

- 패키지를 지정하지 않으면 이름이 없는 '최상위패키지'에 속하는 것으로 지정

- '패키지' : 루트패키지로부터 지정한 패키지에 도달하기 위한 경로

- packge 키워드와 .으로 구별 

- 패키지를 이루는 최상위 선언에는 타입, 함수(최상위함수가 됨), 프로퍼티가 가능하다. > 4장 설명


9. '식으로 사용되는 if문' (=반환값 있는if문) 

- 블럭 마지막에 기재한 값이 반환값

- if-else 모두 있어야 함

- 코틀린 3항 연산자 없음 -> '식으로 사용되는 if문'으로 대체 가능


10. Nothing 타입

- return 은 Nothing 타입으로 간주된다.

- '어떤 식이 Nothing 타입이다' = "프로그램의 순차적 흐름이 그 부분에서 끝나되 정의된 값에 도달하지 못함"을 뜻함

- 모든 타입의 하위 타입으로 간주됨 (어느 위치에든 return을 사용할 수 있는 이유)

- 존재하지 않는 값을 의미 "아예 값이 없다"는 것을 표현

    cf) Unit타입 : "유용한 값이 없다"는 것을 표현


11. 범위, 진행, 연산

 

11-1. 범위표현

   - A..B :  A부터 B까지

   - A until B  :  A부터 B의 전까지

       ㄴ> B가 A보다 적으면 빈범위가 됨

   - A downTo B : B부터 A까지

 

   - 문자열이나 배열 추출 시 유용하다.

"Hello".substring(1 until 4)
IntArray(10){ it * it}.sliceArray( 2..5) // 4,9,16,25

 

11-2. 간격

   - 범위표현 step 간격

 

11-3. 범위 비교

   - in 연산자 : 비교대상이 범위에 속하면 true, 아니면 false

     ㄴ> 비교대상값 in 컨테이너값

               ex) 2 in intArray(3,4,5,)  

     ㄴ> 비교대상값 in 범위표현 

               ex) 2 in 1 until 5 

   - !in 연산자 : 비교대상이 범위에 속하면 false, 아니면 true

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형