You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于Akka Streams中Source.fromFuture返回类型与预期不符的疑问

Understanding Source.fromFuture and mapConcat in Akka Streams

Hey there! Let's clear up this confusion step by step—you're not alone in mixing up how Source.fromFuture works, so let's break it down:

1. What Source.fromFuture actually does

Your core misunderstanding here is about what Source.fromFuture returns. This method doesn't wrap the Future as an element inside the Source. Instead:

  • It takes a Future[T], waits for that future to complete successfully,
  • Then emits the result of the future (your 1 to 10 range) as a single element into the stream,
  • Finally completes the stream.

That's why the return type is akka.stream.scaladsl.Source[scala.collection.immutable.Range.Inclusive, akka.NotUsed]—the stream's elements are the resolved value of the future, not the future itself.

2. How to get your expected Source[Future[Range], NotUsed]

If you actually want the Future to be the element in the Source (so your stream emits the future object, not its result), you should use Source.single instead:

val srcWithFutureAsElement = Source.single(Future.successful(1 to 10))
// Returns: Source[Future[Range.Inclusive], NotUsed]

3. Fixing your mapConcat flow

Your original thought process for using mapConcat makes sense if you had a Source[Future[Range]], but since Source.fromFuture already resolves the future, here's how to achieve the "emit each number from the range" behavior correctly:

import akka.actor.ActorSystem
import akka.stream.scaladsl.{Source, Sink}
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

implicit val system: ActorSystem = ActorSystem("MapConcatExample")

val src = Source.fromFuture(Future.successful(1 to 10))
  .mapConcat(identity) // identity converts the Range (an Iterable[Int]) into individual elements

src.runForeach(println) // Will print 1, 2, ..., 10 one by one

Here, mapConcat(identity) works because Range is an Iterable[Int]—mapConcat takes each element from the source (the range), flattens it into its individual elements, and emits them downstream.

Quick Recap

  • Source.fromFuture(Future[T]) → Source[T, NotUsed]: emits the resolved value of the future
  • Source.single(Future[T]) → Source[Future[T], NotUsed]: emits the future object itself
  • mapConcat works by taking an element that's an Iterable[U] and emitting each U individually, which is perfect for expanding ranges, lists, etc.

内容的提问来源于stack exchange,提问作者joesan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:03:36