https://product.kyobobook.co.kr/detail/S000201206714
아토믹 코틀린 | 브루스 에켈 - 교보문고
아토믹 코틀린 | 코틀린을 익히고 레벨업하는 가장 확실한 방법! 한 번에 하나씩 + 명확한 예제를 실행하면서 + 훌륭한 멘토의 설명으로 배워라!코틀린의 기본 개념을 명확히 이해하고, 더 나은
product.kyobobook.co.kr
4부 함수형 프로그래밍
44. 람다
- 부가적인 장식이 덜 들어간 함수, 함수 리터럴(function literal)
- 무기명
- 다른 코드에 람다 삽입 가능
- 파라미터가 하나인 경우, it 으로 파라미터를 가리키고 더 이상 n -> 사용할 필요 없음
- 함수의 파라미터가 람다뿐이면 람다 주변의 괄호 삭제 가능
- 람다가 특정 인자를 사용하지 않는 경우, 밑줄 사용 가능, 밑줄을 쓰면 람다가 무슨 무슨 인자를 사용하지 않는다는 컴파일러 경우를 무시 가능
- mapIndexed() 를 항상 indices 와 map 으로 대체 불가(일반적)
import atomictest.eq
fun main() {
val list = listOf(1, 2, 3, 4)
val result = list.map({ n: Int -> "[$n]" })
result eq listOf("[1]", "[2]", "[3]", "[4]")
}
import atomictest.eq
fun main() {
val list = listOf('a', 'b', 'c', 'd')
val result =
list.map({ "[${it.uppercaseChar()}]" })
result eq listOf("[A]", "[B]", "[C]", "[D]")
}
import atomictest.eq
fun main() {
val list = listOf('a', 'b', 'c')
list.mapIndexed { index, _ ->
"[$index]"
// list.indices.map {
// "[$it]"
} eq listOf("[0]", "[1]", "[2]")
}
45. 람다의 중요성
- 람다는 문법 설탕으로 보일 수 있지만, 람다는 프로그래밍에 중요한 능력 부여
- 클로저 : 포획, 닫아버리는 것
- 클로저가 없는 람다가 있고, 람다가 없는 클로저가 있을 수 있음
import atomictest.eq
fun main() {
val list = listOf(1, 2, 3, 4)
val isEven = { e: Int -> e % 2 == 0 }
list.filter(isEven) eq listOf(2, 4)
list.any(isEven) eq true
}
46. 컬렉션에 대한 연산
- 객체 컬렉션에 대한 연산을 한꺼번에 수행
- filter() : 주어진 술어와 일치하는 모든 원소가 들어 있는 새 리스트 생성
- any() : 원소 중 어느 하나에 대해 술어가 true 를 반환하면 true 를 반환
- all() : 모든 원소가 술어와 일치하는지 검사
- none() : 술어와 일치하는 원소가 하나도 없는지 검사
- find() 와 firstOrNull() : 모두 술어와 일치하는 첫 번째 원소를 반환, 원소가 없을 때 find() 는 예외 반환, findOrNull() 은 null 반환
- lastOrNull() : 술어와 일치하는 마지막 원소를 반환, 일치하는 원소가 없으면 null 반환
- count() : 술어와 일치하는 원소의 개수 반환
- filterNot() : filter() 반대 그룹 반환
- partition() : 동시에 양쪽 그룹 반환
import atomictest.eq
fun main() {
val list = listOf(-3, -1, 5, 7, 10)
list.filter { it > 0 } eq listOf(5, 7, 10)
list.count { it > 0 } eq 3
list.find { it > 0 } eq 5
list.firstOrNull { it > 0 } eq 5
list.lastOrNull { it < 0 } eq -1
list.any { it > 0 } eq true
list.any { it != 0 } eq true
list.all { it > 0 } eq false
list.all { it != 0 } eq true
list.none { it > 0 } eq false
list.none { it == 0 } eq true
}
import atomictest.eq
fun main() {
val list = listOf(-3, -1, 5, 7, 10)
val isPositive = { i: Int -> i > 0 }
list.filter(isPositive) eq "[5, 7, 10]"
list.filterNot(isPositive) eq "[-3, -1]"
val (pos, neg) = list.partition { it > 0 }
pos eq "[5, 7, 10]"
neg eq "[-3, -1]"
}
47. 멤버 참조
- 함수 인자로 멤버 참조 전달 가능
- 멤버 함수나 프로퍼티 이름 앞에 그들이 속한 클래스 이름과 2중 콜론(::)을 위치시켜서 멤버 참조 생성 가능
package memberreferences1
import atomictest.eq
data class Message(
val sender: String,
val text: String,
val isRead: Boolean
)
fun main() {
val messages = listOf(
Message("Kitty", "Hey!", true),
Message("Kitty", "Where are you?", false))
val unread =
messages.filterNot(Message::isRead)
unread.size eq 1
unread.single().text eq "Where are you?"
}
48. 고차 함수
- 함수형 프로그래밍에 필수 요소
- filter(), map(), any() 등
49. 리스트 조작하기
- 묶기(zipping) 와 평평하게 하기(flattening) 로 List 조작
- 묶기(zipping) : 재킷의 지퍼처럼 두 List 의 원소를 하나씩 짝짓는 방식으로 묶기
- 평평하게 하기(flattening) : 각 원소가 List 인 List 를 읹로 받아서 원소가 따로따로 들어 있는 List 를 반환
import atomictest.eq
fun main() {
val left = listOf("a", "b", "c", "d")
val right = listOf("q", "r", "s", "t")
left.zip(right) eq // [1]
"[(a, q), (b, r), (c, s), (d, t)]"
left.zip(0..4) eq // [2]
"[(a, 0), (b, 1), (c, 2), (d, 3)]"
(10..100).zip(right) eq // [3]
"[(10, q), (11, r), (12, s), (13, t)]"
}
import atomictest.eq
fun main() {
val list = listOf(
listOf(1, 2),
listOf(4, 5),
listOf(7, 8),
)
list.flatten() eq "[1, 2, 4, 5, 7, 8]"
}
50. 맵 만들기
- 맵에 연산 적용 가능
- map(), mapKeys(), mapValues()
import atomictest.eq
fun main() {
val even = mapOf(2 to "two", 4 to "four")
even.map { // [1]
"${it.key}=${it.value}"
} eq listOf("2=two", "4=four")
even.map { (key, value) -> // [2]
"$key=$value"
} eq listOf("2=two", "4=four")
even.mapKeys { (num, _) -> -num } // [3]
.mapValues { (_, str) -> "minus $str" } eq
mapOf(-2 to "minus two",
-4 to "minus four")
even.map { (key, value) ->
-key to "minus $value"
}.toMap() eq mapOf(-2 to "minus two", // [4]
-4 to "minus four")
}
51. 시퀀스
- 코틀린 시퀀스는 List 와 비슷하나, 시퀀스를 대상으로 해서는 이터레이션만 수행 가능
- 인덱스를 써서 시퀀스의 원소에 접근할 수 없음
- 이 제약 조건으로 시퀀스 연산을 아주 효율적으로 연쇄 가능
- 코틀린 시퀀스를 다른 함수형 언어에서는 스트림으로 불림
- 코틀린이 다른 이름으로 선택한 이유는 자바 8 의 스트림 라이브러리와 호환서 유지를 위함
- 즉시 계산 : 수평적 평가, 모든 원소에 대해 연산을 수행함
- 지연 계산 : 수직적 평가, 필요할 때에 연관된 값으로 연산을 수행함
- 내부에 객체의 메모리 주소를 표한하는 것은 '@' 사용
- 시퀀스 연산 : 중간 연산 과 최종 연산
- 중간 연산 : 결과로 다른 시퀀스 반환, filter(), map() 은 중간 연산
- 최종 연산 : 시퀀스가 아닌 값 반환, 저장된 모든 계산 수행, any() 는 최종 연산
package sequences
import atomictest.*
fun Int.isEven(): Boolean {
trace("$this.isEven()")
return this % 2 == 0
}
fun Int.square(): Int {
trace("$this.square()")
return this * this
}
fun Int.lessThanTen(): Boolean {
trace("$this.lessThanTen()")
return this < 10
}
fun main() {
val list = listOf(1, 2, 3, 4)
trace(">>> List:")
trace(
list
.filter(Int::isEven)
.map(Int::square)
.any(Int::lessThanTen)
)
trace(">>> Sequence:")
trace(
list.asSequence()
.filter(Int::isEven)
.map(Int::square)
.any(Int::lessThanTen)
)
trace eq """
>>> List:
1.isEven()
2.isEven()
3.isEven()
4.isEven()
2.square()
4.square()
4.lessThanTen()
true
>>> Sequence:
1.isEven()
2.isEven()
2.square()
4.lessThanTen()
true
"""
}
52. 지역 함수
- 어디에서든 함수를 정의 가능, 함수 안에서도 함수를 정의 가능
- 지역 함수는 클로저
- 람다를 둘러싼 함수가 아니라 람다에서만 반환해야 한다면 레이블이 붙은 return 사용
import atomictest.eq
fun main() {
val list = listOf(1, 2, 3, 4, 5)
val value = 3
var result = ""
list.forEach {
result += "$it"
if (it == value) return@forEach
}
result eq "12345"
}
53. 리스트 접기
- fold() : 리스트의 모든 원소를 순서대로 조합해 결과값을 하나로 생성
import atomictest.eq
fun main() {
val list = listOf(1, 10, 100, 1000)
list.fold(0) { sum, n ->
sum + n
} eq 1111
}
54. 재귀
- 재귀는 함수 안에서 함수 자신을 호출하는 프로그래밍 기법
- 꼬리 재귀는 일부 재귀 함수에 명시적으로 적용할 수 있는 최적화 방법
- tailrec은 꼬리재귀(tail recursive)라는 의미로, 추가적인 연산이 없이 자신 스스로 재귀적으로 호출하다가 어떤 값을 리턴하는 함수를 의미
package recursion
import atomictest.eq
fun fibonacci(n: Int): Long {
tailrec fun fibonacci(
n: Int,
current: Long,
next: Long
): Long {
if (n == 0) return current
return fibonacci(
n - 1, next, current + next)
}
return fibonacci(n, 0L, 1L)
}
fun main() {
(0..8).map { fibonacci(it) } eq
"[0, 1, 1, 2, 3, 5, 8, 13, 21]"
fibonacci(22) eq 17711
fibonacci(50) eq 12586269025
}
'Study' 카테고리의 다른 글
[Book] 아토믹 코틀린 - 7부 파워 툴 (0) | 2024.09.05 |
---|---|
[Book] 아토믹 코틀린 - 5부 객체 지향 프로그래밍 - 2 (0) | 2024.09.05 |
[Book] 아토믹 코틀린 - 2부 객체 소개 - 2 (0) | 2024.09.05 |
[Book] 테스트 주도 개발 시작하기 - Chapter11. 마치며 (0) | 2024.09.05 |
[Book] 테스트 주도 개발 시작하기 - Chapter10. 테스트 코드와 유지보수 (0) | 2024.09.05 |