람다식과 고차 함수 호출하기
- 기존 기본형 변수 : 할당 값은 스택에 저장됨. 인자로 전달하는 경우 값은 복사 되어 전달
- JVM 은 포인터 주소 연산 없음 -> 값을 복사하여 객체 전달. 이때 복사되는 값은 객체의 주소
값에 의한 호출
- 함수가 다른 함수의 인자로 전달 되는 경우 -> 인자로 전달되는 함수는 즉시 수행하여 값을 전달(값으로 처리되기 때문)
- 인자로 전달되는 시점에서 실행 됨
- 람다식 함수의 즉시 실행
- 매개변수에 직접 람다식을 함수 호출 형태로 작성해 줌
ex) val sum = a(lambda())
val lambda: () -> Unit = {}
이름에 의한 람다식 호출
- 실제로 호출할 때 실행
- 변수명에 람다식 자체가 매개변수에 복사됨
(즉시 실행 안하고 전달만 하려면 변수명으로, 즉시 실행할 경우 함수 호출 형태로 사용하면 됨 -> 즉시 실행 안해도 되는 곳에서 필요할 시에만 람다식을 실행 시키는데 용이)
ex) val sum = a(lambda)
fun a(a: () -> Unit) { // a가 람다식 자료형으로 선언됨. 람다식 자체가 매개변수 a에 복사되어 사용전까지 실행되지 않음
return lambda() // 여기서 호출
}
val lambda: () -> Unit = {}
다른 함수의 참조에 의한 일반 함수 호출
- 함수의 인자에 또 다른 함수를 사용하는 고차 함수
- 람다식으로 표현이 가능하면 이름으로 호출이 가능하지만 함수는 람다식이 아니기 때문에 이름으로 호출 불가능
- 인자로 넘겨 줄때 2개의 세미콜론 사용, 매개변수는 함수의 자료형을 명시
ex)
fun sum(a: Int, b: Int) = a + b
// 사용시
val otherVal = ::sum // ::는 함수 참조 기호
람다식의 매개변수
람다식에 매개변수가 없는 경우
- 소괄호를 생략해서 사용 가능
a({"print b"})
a {"print b"} //이렇게 소괄호를 생략해서 작성 가능
람다식의 매개변수가 1개인 경우
a {b -> "print $b"}
파라미터가 한개인 경우 화살표 생략 가능
a {"print $it"} // $it를 사용하여 생략
람다식의 매개변수가 2개인 경우
- 매개변수가 2개 이상인 경우 $it를 사용하여 생략 불가능
- 특정 람다식 사용하고 싶지 않을 때 언더스코어로 대체 가능
일반 매개변수와 람다식 매개변수 같이 사용
함수의 마지막에 람다식을 위치시키면 함수 호출시 함수 소괄호 바깥으로 람다식 분리 가능
일반 함수에 람다식 매개변수 2개 이상 사용하기
소괄호를 완전히 생략하는 것은 불가능하지만 마지막 인자는 소괄호 밖으로 분리 가능
03_4 고차 함수와 람다식 사례
동기화 코드 구현
- 동기화 : 변경이 일어나면 안 되는 특정 코드를 보호하기 위한 잠금 기법 (임계 영역 Critical Section)
- Lock을 사용하여 임계 영역 보호
- 자바에서 제공되는 기능 Lock, ReentrantLock
- 제네릭 : 데이터 자료형을 일반화 하여 어떤 자료형이던 지정할 수 있는 자료형
- try {...} finally {...}
- 공유되는 자원 (전역 변수)는 특정 연산을 수행 하고 있을 때 보호가 필요 함 -> 이때 lock 필요
네트워크 호출 구현
- 네트워크로 부터 호출 후 처리시 성공과 실패에 대한 특정 콜백 함수
- 콜백 함수 : 특정 이벤트 발생 전 까지 처리 x, 이벤트 발생시 즉시 호출. 사용자 시점 x, 시스템이나 이벤트에 따라 호출 시점 결정
코틀린의 다양한 함수
익명함수
변수 선언에 그대로 사용 가능
ex )
val result: (String) -> String = fun(a) = "$a"
result라는 이름으로 다른 곳에서 익명 함수 사용 가능. 람다식과는 다른 개념
람다식에는 return 이나 조건식을 사용하기 어렵기 때문에 익명 함수를 사용 (람다식의 경우 return@라벨이름 형태로 사용. 흐름 제어에서 학습)
인라인 함수
- 함수를 호출한 곳에 함수 본문의 내용을 모두 복사해서 넣기 때문에 코드 성능 △. 분기 없음
- 람다식 매개변수를 가지고 있는 함수에서 동작
- 기존 함수 : 다른 코드로 분기하는 작업 -> 기존 실행 내용 저장 했다가 다른 코드 실행 후 다시 돌아올 때 복구하는 작업 필요. 함수 호출시마다 분기
- inline 을 fun 앞에 선언해서 사용
- 자바로 역컴파일하여 확인 가능
- 인라인 함수 본문 길면 성능 경고 있을 수 있음
- 빈번한 인라인 함수 호출은 코드 양의 증가 -> 성능이 오히려 떨어질 수 있음
- 일부 람다식을 인라인 되지 않게 하려면 noinline 키워드 사용 -> 복사 없이 사용 됨
인라인 함수와 비지역 반환
- 비지역 반환 : 호출한 곳이 아닌 람다식과 같은 다른 곳에서 return 되는 것
- inline 키워드로 선언되지 않은 함수에서 사용된 람다식에서는 return 문 허용 불가. 직접 호출의 경우도 마찬가지로 중첩 실행이 되므로 return 사용 불가
- crossinline 키워드는 비지역 반환 금지해야 하는 람다식에 사용 : 비지역에서 리턴으로 반환되면 안되는 경우나 문맥이 달라지는 곳에서 사용 불가하도록 키워드 사용
확장 함수
- 멤버 메서드 : 클래스에 정의된 다양한 함수
- 확장 함수는 기존 클래스에 원하는 함수를 추가하여 확장시킴. 필요로 하는 대상에 함수를 추가
(tip : 코틀린 최상위 요소 Any에 확장하면 모든 요소에 상속되어 사용 가능)
- 확장하려는 대상에 새로 만든 확장 함수와 같은 멤버 함수나 메서드 존재하는 경우 -> 확장 함수가 낮은 우선 순위! 멤버 메서드가 우선으로 호출
중위 함수
- 중위 표현법 : Infix Notation 클래스 멤버 호출시 점연산자 생략하고 소괄호 사용 x. 직관적 이름 사용하는 표현법. 중위 연산자 처럼 표현 가능
- 조건 : 멤버 메서드 또는 확장 함수여야 함. 하나의 매개변수를 가져야 함. infix 키워드 사용하여 정의
꼬리 재귀 함수
- 재귀 : 자기 자신을 다시 참조하는 방법
- 스택 오버플로우 오류 발생 가능성이 있기 때문에 무한 호출 되지 않도록 탈출 조건 만들것. 스택 영역 이용하므로 호출 횟수 적당히 지정하여 연산. 코드를 복잡하게 하지 않을 것.
- 코틀린에서 스택 오버플로우 해결을 위해 꼬리 재귀 함수 사용. 스택에 계속 쌓이는 방법 아닌 꼬리 무는 형태
- tailrec 키워드 사용
- 함수가 계산을 먼저 할 수 있도록 함수를 작성해야 함
03_6 함수와 변수의 범위
최상위 함수와 지역 함수
- 지역 함수 : 함수 안에 또 다른 함수가 선언되어 있는 경우
- 주의 : 사용자 함수는 선언부 위치에 상관없이 접근 가능하지만 지역 함수의 경우 선언부가 먼저 나와야 컴파일 되서 사용 가능 -> 지역 함수를 사용할 때는 항상 지역 함수를 먼저 선언해야 함(선언 순서에 영향을 받음)
지역 변수와 전역 변수
- 지역 변수 : 특정 콬드 블록 안에 있는 변수. 블록을 벗어나는 경우 프로그램 메모리에서 삭제되므로 더 이상 사용 할 수 없음
- 전역 변수 : 최상위에 있는 변수. 프로그램 실행되는 동안 삭제되지 않음. 메모리에 유지됨. 동시 접근 코드는 잘못된 동작 유발 가능. 동기화 코드 구현 참고
- 최상위에 선언된 전역 변수 범위는 패키지 전체
- 주의 : 지역 함수에 있는 지역 변수의 경우 상위 함수의 변수명과 같더라도 지역 변수이기 때문에 각자 값을 가진다. 지역 함수에서 상위 함수에 있는 변수 접근 가능
참고 도서 : Do it 코틀린 프로그래밍
http://www.yes24.com/Product/Goods/74035266
'NSLog(@"%@", dailyLog)' 카테고리의 다른 글
[Kotlin 20200804] 객체 지향 프로그래밍 - 인터페이스 (0) | 2020.08.04 |
---|---|
[Kotlin 20200803] 객체 지향 프로그래밍 (0) | 2020.08.03 |
[Kotlin 20200802] 객체 지향 프로그래밍 - 클래스와 객체 (0) | 2020.08.03 |
[Kotlin 20200730] 프로그램 흐름 제어 (0) | 2020.07.30 |
자원 고갈 공격 SYN 플러딩 (SYN Flooding) (0) | 2020.07.27 |
댓글