Они действительно тесно связаны.Вы могли бы сказать, что CoroutineScope
формализует способ наследования CoroutineContext
.
CoroutineScope
не имеет данных сам по себе, он просто содержит CoroutineContext
.Его ключевая роль заключается в том, что он является неявным получателем блока, который вы передаете launch
, async
и т. Д.
См. Этот пример:
runBlocking {
val scope0 = this
// scope0 is the top-level coroutine scope.
scope0.launch {
val scope1 = this
// scope1 inherits its context from scope0. It replaces the Job field
// with its own job, which is a child of the job in scope0.
// It retains the Dispatcher field so the launched coroutine uses
// the dispatcher created by runBlocking.
scope1.launch {
val scope2 = this
// scope2 inherits from scope1
}
}
}
Вы можете увидеть, как CoroutineScope
опосредует наследование сопрограммных контекстов.Если вы отмените задание в scope1
, это будет распространяться на scope2
и отменяет также и задание launch
ed.
Обратите внимание на ключевую синтаксическую особенность: я явно написал scope0.launch
, но имелЯ написал только launch
, это будет означать точно то же самое.Вот как CoroutineScope
помогает «автоматически» распространять область видимости.