0Pricing
Scala for Backend Engineering & Functional Programming · Aula

Origem, fluxo e destino

Os blocos de construção de fluxos de dados.

Origem, fluxo e destino é uma aula grátis de Scala for Backend Engineering & Functional Programming no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Scala for Backend Engineering & Functional Programming, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Scala for Backend Engineering & Functional Programming inclui 4 aulas no total.

Os três blocos de construção

O Akka Streams modela um fluxo de dados como um grafo de etapas de processamento. As três etapas lineares principais são Fonte (produz elementos), Fluxo (transforma elementos) e Destino (consome elementos).

Uma Fonte tem uma saída, um Destino tem uma entrada e um Fluxo tem exatamente uma entrada e uma saída. Conectá-los descreve o que deve acontecer, não quando.

Definindo uma Fonte

Uma Source[Out, Mat] emite elementos do tipo Out e expõe um valor materializado do tipo Mat. As fontes mais simples vêm de coleções ou intervalos mantidos na memória.

Até que o fluxo seja executado, uma Source é apenas um modelo imutável que pode ser reutilizado livremente.

import akka.stream.scaladsl.Source

val numbers: Source[Int, akka.NotUsed] =
  Source(1 to 100)

val single: Source[String, akka.NotUsed] =
  Source.single("hello")

Definindo um Destino

Um Sink[In, Mat] consome elementos do tipo In. O valor materializado geralmente captura o resultado do consumo, como um Future que é concluído quando o fluxo termina.

Sink.foreach executa um efeito colateral para cada elemento; Sink.fold acumula um único resultado.

import akka.stream.scaladsl.Sink
import scala.concurrent.Future

val printSink: Sink[Int, Future[akka.Done]] =
  Sink.foreach(println)

val sumSink: Sink[Int, Future[Int]] =
  Sink.fold(0)(_ + _)

Definindo um Fluxo

Um Flow[In, Out, Mat] fica entre uma Source e um Sink, transformando cada elemento. Os Flows são reutilizáveis por si só e podem ser compostos antes de serem conectados a qualquer extremidade.

Aqui, um Flow duplica números inteiros e os converte em cadeias de caracteres.

import akka.stream.scaladsl.Flow

val doubleToString: Flow[Int, String, akka.NotUsed] =
  Flow[Int]
    .map(_ * 2)
    .map(n => s"value=$n")

Conectando uma Fonte a um Destino

O operador via conecta um Flow a uma Source, e to conecta um Sink. Conectar diretamente uma Source a um Sink com to produz um RunnableGraph: um modelo fechado e executável.

Nenhum elemento se move ainda; isso apenas descreve a topologia.

import akka.stream.scaladsl.{Source, Sink, RunnableGraph}

val graph: RunnableGraph[akka.NotUsed] =
  Source(1 to 10).to(Sink.foreach(println))

via: inserindo um Fluxo

Use via para inserir um Flow no pipeline. Uma Source.via(flow) produz uma nova Source cujo tipo de saída corresponde ao tipo de saída do Flow.

Encadear chamadas de via permite criar longos pipelines de transformação a partir de pequenos componentes Flow testáveis.

val pipeline =
  Source(1 to 10)
    .via(Flow[Int].filter(_ % 2 == 0))
    .via(Flow[Int].map(_ * 10))
    .to(Sink.foreach(println))

Segurança de tipos entre etapas

O compilador garante que o tipo de saída de cada etapa corresponda ao tipo de entrada da etapa seguinte. Uma Source[Int] não pode ser conectada a um Sink[String] sem um Flow intermediário que converta o tipo.

Essa verificação estática detecta erros na conexão do pipeline antes da execução.

// Source[Int] -> Flow[Int, String] -> Sink[String]
val ok =
  Source(1 to 3)
    .via(Flow[Int].map(_.toString))
    .to(Sink.foreach[String](println))

Valores materializados

Cada modelo carrega um valor materializado: uma referência produzida quando o fluxo é executado. Um Sink.fold materializa um Future do resultado. Por padrão, combinar etapas mantém o valor materializado mais à esquerda (NotUsed para fontes simples).

Use toMat e Keep para selecionar o valor do lado que deseja.

import akka.stream.scaladsl.Keep
import scala.concurrent.Future

val g: RunnableGraph[Future[Int]] =
  Source(1 to 100)
    .toMat(Sink.fold(0)(_ + _))(Keep.right)

Componentes reutilizáveis

Como Sources, Flows e Sinks são valores imutáveis, você pode defini-los uma vez e reutilizá-los em vários pipelines. Isso incentiva a criação de uma biblioteca de pequenas etapas de processamento nomeadas.

Um Flow definido para análise pode ser inserido tanto em um pipeline de arquivo quanto em um pipeline HTTP.

val parse: Flow[String, Int, akka.NotUsed] =
  Flow[String].map(_.trim.toInt)

val fromFile  = lines.via(parse)
val fromHttp  = requestBody.via(parse)

Construtores comuns de Source

O Akka Streams fornece várias fábricas de Source: Source.single, Source.repeat, Source.tick para emissão temporizada, Source.future a partir de um Future e Source.empty.

Escolher o construtor adequado torna explícita a intenção do produtor de dados.

import scala.concurrent.duration._

val ticks  = Source.tick(0.seconds, 1.second, "tick")
val onceF  = Source.future(scala.concurrent.Future.successful(42))
val forever = Source.repeat("x")

Construtores comuns de Sink

Da mesma forma, entre os sinks estão Sink.head (o primeiro elemento como Future), Sink.seq (coleta tudo em uma Seq), Sink.ignore (drena e descarta) e Sink.last.

Para pipelines que devolvem um resultado ao seu código, Sink.seq e Sink.fold são os mais comuns.

import scala.concurrent.Future

val collect: Sink[Int, Future[Seq[Int]]] = Sink.seq
val firstOne: Sink[Int, Future[Int]]    = Sink.head
val drain: Sink[Int, Future[akka.Done]] = Sink.ignore

Verificação rápida

Teste sua compreensão dos tipos de etapas lineares.

Recapitulação

Você aprendeu os três blocos de construção lineares: Fonte produz, Fluxo transforma e Destino consome. Eles são modelos imutáveis e reutilizáveis, conectados com via e to.

Conectar uma Source a um Sink produz um RunnableGraph que carrega um valor materializado, mas não move nenhum dado até ser executado. Em seguida, você transformará fluxos com operadores mais avançados.

Perguntas Frequentes

A aula “Origem, fluxo e destino” é grátis?

Sim — o texto completo de “Origem, fluxo e destino” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Scala for Backend Engineering & Functional Programming, atualize para CoddyKit PRO. O curso de Scala for Backend Engineering & Functional Programming inclui 4 aulas no total.

O que vou aprender em “Origem, fluxo e destino”?

Os blocos de construção de fluxos de dados. Você pratica Scala for Backend Engineering & Functional Programming com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Scala for Backend Engineering & Functional Programming?

Nenhuma experiência prévia é necessária. Scala for Backend Engineering & Functional Programming no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.

Quanto tempo leva a aula “Origem, fluxo e destino”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Scala for Backend Engineering & Functional Programming?

Sim. Cada aula de Scala for Backend Engineering & Functional Programming inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Origem, fluxo e destino
  2. Transformando fluxos
  3. Contrapressão
  4. Executando um pipeline
← Voltar para Scala for Backend Engineering & Functional Programming