Scala for Backend Engineering & Functional Programming · Aula

Closures

Capture estado.

Aula 4 de 413 etapas

Closures é uma aula grátis de Scala for Backend Engineering & Functional Programming no CoddyKit. Esta é a aula 4 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.

O que é uma closure?

Uma closure é uma função que captura variáveis do escopo ao redor em que foi definida. Ela mantém uma referência a essas variáveis, continuando a acessá-las mesmo depois que esse escopo termina.

object Main {
  def main(args: Array[String]): Unit = {
    val factor = 3
    val multiply = (x: Int) => x * factor
    println(multiply(5))
  }
}

Capturando uma variável livre

Em x => x * factor, x é um parâmetro, mas factor é uma variável livre obtida do escopo externo. A função mantém uma referência a ela.

object Main {
  def main(args: Array[String]): Unit = {
    val greeting = "Hello"
    val greet = (name: String) => s"$greeting, $name!"
    println(greet("Ann"))
    println(greet("Bob"))
  }
}

As closures sobrevivem ao escopo

Quando uma função retorna uma closure, as variáveis capturadas permanecem vivas enquanto a closure existir, mesmo que a função que a definiu já tenha terminado.

object Main {
  def makeAdder(n: Int): Int => Int = x => x + n
  def main(args: Array[String]): Unit = {
    val add10 = makeAdder(10)
    val add100 = makeAdder(100)
    println(add10(5))
    println(add100(5))
  }
}

Cada closure tem sua própria captura

Chamar uma fábrica de funções duas vezes produz duas closures independentes, cada uma lembrando seu próprio valor capturado.

object Main {
  def prefixer(p: String): String => String = s => p + s
  def main(args: Array[String]): Unit = {
    val withDr = prefixer("Dr. ")
    val withMr = prefixer("Mr. ")
    println(withDr("Smith"))
    println(withMr("Jones"))
  }
}

Capturando estado mutável

Uma closure pode capturar uma var e tanto lê-la quanto atualizá-la. Isso permite que uma closure mantenha estado entre chamadas, como um contador.

object Main {
  def main(args: Array[String]): Unit = {
    var count = 0
    val increment = () => { count += 1; count }
    println(increment())
    println(increment())
    println(increment())
  }
}

Uma fábrica de contadores

Combine as ideias: uma função que retorna uma closure capturando sua própria var privada fornece um contador encapsulado e independente.

object Main {
  def counter(): () => Int = {
    var n = 0
    () => { n += 1; n }
  }
  def main(args: Array[String]): Unit = {
    val c1 = counter()
    val c2 = counter()
    println(c1())
    println(c1())
    println(c2())
  }
}

As closures capturam referências, não cópias

Uma closure captura a variável, não uma cópia instantânea. Se a var capturada mudar depois que a closure for criada, a closure verá o novo valor.

object Main {
  def main(args: Array[String]): Unit = {
    var msg = "first"
    val show = () => println(msg)
    show()
    msg = "second"
    show()
  }
}

Prefira capturar val

Capturar uma val imutável evita surpresas: o valor capturado nunca muda, então a closure se comporta de maneira previsível. Prefira a captura de val em código funcional.

object Main {
  def main(args: Array[String]): Unit = {
    val taxRate = 0.2
    val withTax = (price: Double) => price * (1 + taxRate)
    println(withTax(100))
  }
}

Closures com métodos de coleções

Lambdas passadas para map, filter etc. são closures sempre que fazem referência a variáveis externas. Isso é extremamente comum no uso cotidiano de Scala.

object Main {
  def main(args: Array[String]): Unit = {
    val threshold = 3
    val nums = List(1, 2, 3, 4, 5)
    val big = nums.filter(_ > threshold)
    println(big)
  }
}

Uma armadilha de captura em laços

Em Scala, a variável de um laço for é uma nova associação a cada iteração, portanto as closures capturam valores distintos. Isso evita um erro clássico presente em algumas outras linguagens.

object Main {
  def main(args: Array[String]): Unit = {
    val fns = for (i <- 1 to 3) yield () => i
    println(fns.map(f => f()))
  }
}

Closures encapsulam comportamento + dados

Uma closure combina comportamento (o corpo da função) com dados (as variáveis capturadas). Essa é uma alternativa simples a um pequeno objeto com um método.

object Main {
  def discounter(rate: Double): Double => Double = price => price * (1 - rate)
  def main(args: Array[String]): Unit = {
    val sale = discounter(0.25)
    println(sale(80))
    println(sale(200))
  }
}

Verificação rápida

O que uma closure captura do escopo ao seu redor?

Recapitulação

Você aprendeu sobre closures:

  • Uma closure captura variáveis livres do escopo que a envolve
  • As variáveis capturadas sobrevivem à função que as definiu
  • Cada instância de closure tem seu próprio estado capturado
  • As closures capturam referências, portanto as capturas mutáveis podem mudar
  • Lambdas usadas com map/filter são closures comuns no dia a dia
Grátis para começar

Aprenda Scala com um tutor de IA — grátis

Escreva e execute código real no seu navegador, obtenha ajuda instantânea de um tutor de IA 24/7 e continue de onde parou na web ou no app.

Cursos
39
Aulas
143

Perguntas Frequentes

A aula “Closures” é grátis?

Sim — o texto completo de “Closures” é 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 “Closures”?

Capture estado. 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 4 de 4.

Quanto tempo leva a aula “Closures”?

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. Funções como valores
  2. Currying
  3. Composição
  4. Closures
← Voltar para Scala for Backend Engineering & Functional Programming