+ 항공대학교 김철기 교수님의 객체 지향 프로그래밍 과목 내용를 정리한 글입니다.
고차 함수
- 함수를 파라미터로 받는 함수이다.
fun initializeIntArray(n: Int, initializer: (Int) -> Int): IntArray {
// initializer라는 (Int) -> Int 함수 타입의 변수를 파라미터로 받는다.
// (Int) -> Int는 Int를 파라미터로 받아서 Int를 반환하는 함수 타입
val arr = IntArray(n) // 0으로 초기화 된 n개의 정수를 갖는 배열
for (i in 0 until n) {
arr[i] = initializer(i)
// initializer 함수에 i를 넣은 값을 arr[i]에 저장
}
return arr
}
fun main() {
val squares_1 = IntArray(5) {it * it} // 각 요소가 인덱스의 제곱으로 초기화
val squares_2 = IntArray(5, {it -> it * it})
// {it -> it * it} 라는 람다 함수가 IntArray() 생성자의 두 번째 파라미터
// {it -> it * it}는 it를 인자로 받아서 it * it 값을 반환하는 람다 함수
println(squares_1.joinToString()) // 0, 1, 4, 9, 16
println(squares_2.joinToString()) // 0, 1, 4, 9, 16
val squares_3 = initializeIntArray(5, {it -> it * it})
println(squares_3.joinToString()) // 0, 1, 4, 9, 16
val squares_4 = initializeIntArray(5) {it -> it * it} // 인자를 분리할 수 있다.
println(squares_3.joinToString()) // 0, 1, 4, 9, 16
}
고차 함수의 예 (1)
- 정수 배열의 요소들 중 조건에 만족하는 요소의 개수를 반환하는 함수
=> 바뀐게 크지 않은 비슷한 함수를 여러 개 생성하여 낭비가 크다.
fun countEven(arr: IntArray): Int { // 짝수 개수
var count = 0
for (elem in arr) {
if (elem % 2 == 0) count ++
}
return count
}
fun countMinus(arr: IntArray): Int { // 음수 개수
var count = 0
for (elem in arr) {
if (elem < 0) count ++
}
return count
}
fun countZero(arr: IntArray): Int { // 0의 개수
var count = 0
for (elem in arr) {
if (elem == 0) count ++
}
return count
}
fun main() {
val arr = intArrayOf(-2, -1, 0, 1, 2, 3, 4, 5)
println(countEven(arr)) // 4
println(countMinus(arr)) // 2
println(countZero(arr)) // 1
}
- 고차 함수를 이용하여 여러 함수를 통합하고 낭비를 줄일 수 있다.
fun countIntarray(arr: IntArray, isTrue: (Int) -> Boolean): Int {
// isTrue 함수를 파라미터로 받는다.
// isTrue: Int형을 인자로 받아서 Boolean을 반환하는 함수
var count = 0 // 조건에 만족하는 요소 개수
for (elem in arr) {
if (isTrue(elem)) count ++
}
return count
}
fun main() {
val arr = intArrayOf(-2, -1, 0, 1, 2, 3, 4, 5)
println(countIntarray(arr, {elem -> elem % 2 == 0})) // 4
println(countIntarray(arr, {elem -> elem < 0})) // 2
println(countIntarray(arr, {elem -> elem == 0})) // 1
}
고차 함수의 예 (2)
- 정수 배열의 요소들을 모두 연산한 값을 반환하는 함수
=> 바뀐게 크지 않은 비슷한 함수를 여러 개 생성하여 낭비가 크다.
fun sum(numbers: IntArray): Int { // 배열의 요소들의 합을 구하는 함수
var result = 0
for (elem in numbers) {
result += elem
}
return result
}
fun prod(numbers: IntArray): Int { // 배열의 요소들의 곱을 구하는 함수
var result = 1
for (elem in numbers) {
result *= elem
}
return result
}
fun max(numbers: IntArray): Int { // 배열의 요소들 중 가장 큰 값을 구하는 함수
var result = Int.MIN_VALUE // Int로 표현할 수 있는 가장 작은 값
for (elem in numbers) {
result = if (result > elem) result else elem // 더 큰 값으로 갱신
}
return result
}
fun main() {
val arr = intArrayOf(-2, -1, 1, 2, 3, 4, 5)
println(sum(arr)) // 12
println(prod(arr)) // 240
println(max(arr)) // 5
}
- 고차 함수를 이용하여 여러 함수를 통합하고 낭비를 줄일 수 있다.
fun aggregate(arr: IntArray, initvalue: Int, op: (Int, Int) -> Int): Int {
var result = initvalue
for (elem in arr) {
result = op(result, elem)
}
return result
}
fun main() {
val arr = intArrayOf(-2, -1, 1, 2, 3, 4, 5)
println(aggregate(arr, 0, {result, elem -> result + elem})) // 12
println(aggregate(arr, 1, {result, elem -> result * elem})) // 240
println(aggregate(arr, Int.MIN_VALUE, { result, elem -> if (result > elem) result else elem})) // 5
}
함수의 타입
- op라는 파라미터 함수는 Int와 Int를 첫 번째와 두 번째 인자로 받고, Int 값을 반환한다.
fun aggregate(arr: IntArray, initvalue: Int, op: (Int, Int) -> Int)
- 반환 값 앞에 -> 를 사용한다. (':' 대신)
- 함수의 인자가 여러 개일 경우, 선언 시에 꼭 괄호를 붙여야 한다.
(사용 시에는 괄호를 사용하지 않는다.)
- 반환 값이 없을 때는 -> Unit 을 사용하여 반드시 명시해야 한다.
fun decorativePrintArray(arr: IntArray, prt: (Int) -> Unit)
- 파라미터에 이름을 붙이는 것도 가능하다. (프로그래머에게 힌트 제공)
fun aggregate(arr: IntArray, initvalue: Int, op: (resultSoFar: Int, nextValue: Int) -> Int): Int
람다 함수
- resultSoFar와 nextValue를 파라미터로 갖는 람다 함수
{resultSoFar, nextValue -> resultSoFar + nextValue}
- resultSoFar와 nextValue의 타입은 함수의 파라미터 선언에 명시되기 때문에 명시하지 않는다. (타입 추론)
- 반환 값의 타입도 파라미터의 선언으로부터 유추 가능하므로 명시하지 않는다.
- 다른 인자를 분리하여 람다 함수 앞에서 괄호를 닫고, 그 뒤에 람다 함수를 작성하는 것이 더 바람직하다.
(가독성이 더 높다.)
- 람다 함수의 마지막 문장의 식이 람다 함수의 결과 값이다.
fun aggregate(arr: IntArray, initvalue: Int, op: (resultSoFar: Int, nextValue: Int) -> Int): Int {
var result = initvalue
for (elem in arr) {
result = op(result, elem)
}
return result
}
fun main() {
val arr = intArrayOf(-2, -1, 1, 2, 3, 4, 5)
println(aggregate(arr, 0) {result, elem ->
println("$result += $elem")
result + elem}) // 12
}
단순한 파라미터의 람다 함수
- 파라미터가 없는 람다 함수는 -> 기호의 생략이 가능하다.
fun measureTime(action: () -> Unit): Long { // 작업의 실행 시간을 측정
val start = System.nanoTime() // 현재 시간을 ns단위로 측정
action() // 작업 실행
return System.nanoTime() - start // 작업 후 시간과 차이 반환
}
fun main() {
val time = measureTime {1 + 2} // 파라미터가 없는 람다 함수이므로 -> 기호 생략
println(time)
}
- 파라미터가 하나인 람다 함수는 ->를 생략할 경우 파라미터를 it이라고 지칭한다.
val arr1 = IntArray(10) {n -> n * n}
val arr2 = IntArray(10) {it * it} // 위 식을 간략화
람다 함수 내의 사용하지 않는 파라미터
- 사용하지 않는 파라미터는 밑줄 기호(_)로 지정한다.
fun check(s: String, condition: (Int, Char) -> Boolean) : Boolean {
// 문자열 s의 각 문자들 중 condition을 만족하는 문자가 있다면 false를 반환
for (i in s.indices) {
if (condition(i, s[i])) return false
}
return true
}
fun main() {
println(check("Hello") { _, c -> !c.isLetter() }) // 글자인지 체크 (i가 필요 없다.)
println(check("Hello") { i, c -> i != 0 && c.isUpperCase() }) // 첫 글자외 문자가 소문자라면 true
// 첫 글자를 조건에서 제외하기 위해 i 사용
}
익명 함수 (람다 함수의 대안)
- fun 예약어를 이용하여 함수 이름만 제외하여 함수를 선언한다.
- 람다 함수의 형태
val total = aggregate(array) {res, elm -> res + elm}
- 익명 함수의 형태
val total = aggregate(array, fun(res, elm) = res + elm)
또는
val total = aggregate(array, fun(res, elm): Boolean {return res + elm})
- 익명 함수는 맨 뒤 파라미터라 해도 괄호를 미리 닫을 수 없다.
val total = aggregate(array) fun(res, elm): Boolean {return res + elm} // 불가
이미 존재하는 함수를 파라미터로 넘기기
- 이미 add라는 함수가 존재할 때, ::를 사용하여 함수의 파라미터로 add 함수 자체를 넘길 수 있다.
fun aggregate(arr: IntArray, initvalue: Int, op: (Int, Int) -> Int) :Int {
var result = initvalue
for (elem in arr) {
result = op(result, elem)
}
return result
}
fun add(a: Int, b: Int): Int {
return a + b
}
fun main() {
val arr = intArrayOf(1, 2, 3, 4, 5)
println(aggregate(arr, 0) {result, elm -> add(result, elm)})
println(aggregate(arr, 0, ::add))
}'Study > Kotlin Study' 카테고리의 다른 글
| [Kotlin] 영역 함수 (0) | 2023.10.09 |
|---|---|
| [Kotlin] 확장 (0) | 2023.10.09 |
| [Kotlin] 객체 (Object) (0) | 2023.09.17 |
| [Kotlin] 단순한 변수 이상인 프로퍼티 (0) | 2023.09.17 |
| [Kotlin] 널 가능성 (0) | 2023.09.12 |