I assume in both examples, you are wrapping the call in something that provides a
CoroutineScope
as a receiver (e.g.
runBlockng()
). In the first example, the
launch
is from the
CoroutineScope
receiver, i.e. it is equivalent to
fun main() = runBlocking { // this: CoroutineScope
flow {
// ...
}.collectLatest { value ->
this@runBlocking.launch { // (coroutineScope from runBlocking).launch()
println("start: $value")
while(true) {
delay(200L)
println("loop: $value")
}
}
}
}
which it just launches the
Job
and returns in
collectLatest()
instantly and never canceled by
collectLatest()
. However, in the second case,
coroutineScope()
provides the
CoroutineScope
of the current coroutine, which is the one provided by
collectLatest()
and can be cancelled by it.