일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 스택 자바 코드
- ar vr 차이
- 스택 큐 차이
- 멤버변수
- android retrofit login
- 서비스 vs 쓰레드
- 안드로이드 유닛 테스트
- ANR이란
- 안드로이드 유닛테스트란
- 서비스 쓰레드 차이
- jvm 작동 원리
- android ar 개발
- 안드로이드 os 구조
- 안드로이드 레트로핏 사용법
- rxjava cold observable
- rxjava hot observable
- 객체
- jvm이란
- Rxjava Observable
- 안드로이드 라이선스 종류
- 안드로이드 레트로핏 crud
- 안드로이드 유닛 테스트 예시
- 2022 플러터 안드로이드 스튜디오
- 클래스
- 플러터 설치 2022
- 큐 자바 코드
- rxjava disposable
- 자바 다형성
- 2022 플러터 설치
- 안드로이드 라이선스
- Today
- Total
나만을 위한 블로그
[코틀린 코루틴] 2. 시퀀스 빌더 본문
파이썬, 자바스크립트 등 언어에선 제한된 형태의 코루틴을 쓰고 있다.
- 비동기 함수(async, await)
- 제너레이터 함수(값을 순차적으로 리턴하는 함수)
코틀린에는 제너레이터 대신 시퀀스를 생성할 때 사용하는 시퀀스 빌더가 있다. 시퀀스는 List, Set 같은 컬렉션과 비슷한 개념이지만 필요할 때마다 값을 하나씩 계산하는 지연 처리를 한다. 시퀀스의 특징은 아래와 같다.
- 요구되는 연산을 최소한으로 수행
- 무한정이 될 수 있음
- 메모리 사용이 효율적 (이펙티브 코틀린 아이템 49 참고)
이런 특징 때문에 값을 순차 계산해서 필요할 때 리턴하는 빌더를 정의하는 게 좋다. 시퀀스는 sequence 함수로 정의하며 람다식 안에선 yield 함수를 호출해 시퀀스의 다음 값을 생성한다.
val seq = sequence { // this : SequenceScope<Int>
yield(1)
yield(2)
yield(3)
}
fun main() {
for (num in seq) {
print(num)
}
}
// 123
sequence 함수는 짧은 DSL 코드고 인자는 수신 객체 지정 람다 함수다. 람다 안에서 수신 객체인 this는 sequenceScope<T>를 가리킨다. 이 객체는 yield 함수를 갖고 있다.
반드시 알아야 하는 건 각 숫자가 미리 생성되는 대신 필요할 때마다 생성된다는 것이다. 시퀀스 빌더 내부, 시퀀스를 쓰는 곳에서 메시지를 출력하면 작동 방식을 쉽게 알 수 있다.
val seq = sequence {
println("Generating First")
yield(1)
println("Generating Second")
yield(2)
println("Generating Third")
yield(3)
println("Done!")
}
fun main() {
for (num in seq) {
println("Next Number : $num")
}
}
// Generating First
// Next Number : 1
// Generating Second
// Next Number : 2
// Generating Third
// Next Number : 3
// Done!
1번째 수를 요청하면 빌더 내부로 진입하고 Generating First를 출력한 뒤 1을 리턴한다. 이후 반복문에서 리턴된 값을 받고 Next Number : 1을 출력한다.
여기서 반복문과 다른 결정적 차이는, 이전에 다른 숫자를 찾기 위해 멈췄던 지점에서 재실행된다. 중단 체제가 없으면 함수가 중간에 멈췄다가 나중에 중단된 지점에서 다시 실행되는 건 불가능하다. 중단이 가능해서 메인 함수와 시퀀스 제너레이터가 번갈아가며 실행된다.
실제 사용 예
시퀀스 빌더가 쓰이는 전형적 예시는 피보나치 수열 같은 수학적 시퀀스를 만드는 것이다.
import java.math.BigInteger
val fibonacci: Sequence<BigInteger> = sequence {
var first = 0.toBigInteger()
var second = 1.toBigInteger()
while (true) {
yield(first)
val temp = first
first += second
second = temp
}
}
fun main() {
println(fibonacci.take(10).toList())
}
// [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
또는 난수, 임의의 문자열을 만들 때도 쓸 수 있다.
import kotlin.random.Random
fun randomNumbers(
seed: Long = System.currentTimeMillis()
): Sequence<Int> = sequence {
val random = Random(seed)
while (true) {
yield(random.nextInt())
}
}
fun randomUniqueStrings(
length: Int,
seed: Long = System.currentTimeMillis()
): Sequence<String> = sequence {
val random = Random(seed)
val charPool = ('a'..'z') + ('A'..'Z') + ('0'..'9')
while (true) {
val randomString = (1..length)
.map { i -> random.nextInt(charPool.size) }
.map { charPool::get }
.joinToString("")
yield(randomString)
}
}.distinct()
시퀀스 빌더는 yield가 아닌 중단 함수를 쓰면 안 된다. 중단이 필요하다면 데이터를 갖고 오기 위해 Flow를 쓰는 게 낫다.
'책 > 코틀린 코루틴' 카테고리의 다른 글
[코틀린 코루틴] 8. Job, 자식 코루틴 기다리기 (0) | 2024.02.17 |
---|---|
[코틀린 코루틴] 7. 코루틴 컨텍스트 (0) | 2024.02.17 |
[코틀린 코루틴] 6. 코루틴 빌더 (0) | 2024.02.16 |
[코틀린 코루틴] 3. 중단은 어떻게 작동하는가 (0) | 2024.02.14 |
[코틀린 코루틴] 1. 코루틴을 배워야 하는 이유 (0) | 2024.02.10 |