아래 책 공부하며 '새롭게 배운 점', '더 궁금해진 것', '자주 까먹는 부분'들에 대한 포스팅입니다.
코틀린 완벽 가이드 입문부터 활용까지, 필요한 지식 총망라!
페이지 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