Chamada por nome: => Tipo
A => Typenotação significa chamada por nome, que é uma das muitas maneiras pelas quais os parâmetros podem ser transmitidos. Se você não estiver familiarizado com eles, recomendo reservar um tempo para ler esse artigo da Wikipedia, mesmo que hoje em dia seja principalmente por valor e por referência.
O que isso significa é que o que é passado é substituído pelo nome do valor dentro da função. Por exemplo, considere esta função:
def f(x: => Int) = x * x
Se eu chamar assim
var y = 0
f { y += 1; y }
Então o código será executado assim
{ y += 1; y } * { y += 1; y }
Embora isso levante o ponto do que acontece se houver um conflito de nome de identificador. Na chamada tradicional por nome, um mecanismo chamado substituição para evitar captura ocorre para evitar conflitos de nome. No Scala, no entanto, isso é implementado de outra maneira com o mesmo resultado - nomes de identificadores dentro do parâmetro não podem se referir ou identificadores de sombra na função chamada.
Existem alguns outros pontos relacionados à chamada por nome dos quais falarei depois de explicar os outros dois.
Funções de aridade 0: () => Tipo
A sintaxe () => Typerepresenta o tipo de a Function0. Ou seja, uma função que não aceita parâmetros e retorna algo. Isso é equivalente a, digamos, chamar o método size()- ele não usa parâmetros e retorna um número.
É interessante, no entanto, que essa sintaxe seja muito semelhante à sintaxe para uma literal de função anônima , que é a causa de alguma confusão. Por exemplo,
() => println("I'm an anonymous function")
é uma função anônima literal de arity 0, cujo tipo é
() => Unit
Para que pudéssemos escrever:
val f: () => Unit = () => println("I'm an anonymous function")
É importante não confundir o tipo com o valor, no entanto.
Unidade => Tipo
Esta é realmente apenas um Function1, cujo primeiro parâmetro é do tipo Unit. Outras maneiras de escrever seria (Unit) => Typeou Function1[Unit, Type]. A questão é ... é improvável que isso seja o que se quer. O Unitobjetivo principal do tipo é indicar um valor pelo qual não se interessa, portanto, não faz sentido receber esse valor.
Considere, por exemplo,
def f(x: Unit) = ...
O que alguém poderia fazer x? Ele pode ter apenas um único valor, portanto, não é necessário recebê-lo. Um possível uso seria o encadeamento de funções retornando Unit:
val f = (x: Unit) => println("I'm f")
val g = (x: Unit) => println("I'm g")
val h = f andThen g
Como andThensó está definido Function1e as funções que estamos encadeando estão retornando Unit, tivemos que defini-las como sendo do tipo Function1[Unit, Unit]para poder encadear elas.
Fontes de confusão
A primeira fonte de confusão é pensar que a semelhança entre tipo e literal que existe para funções de aridade 0 também existe para chamada por nome. Em outras palavras, pensando que, porque
() => { println("Hi!") }
é literal para () => Unit, então
{ println("Hi!") }
seria um literal para => Unit. Não é. Isso é um bloco de código , não um literal.
Outra fonte de confusão é que Unito valor desse tipo é gravado (), que se parece com uma lista de parâmetros de 0-arity (mas não é).
case class Scheduled(time: Int)(callback: => Unit). Isso funciona porque a lista de parâmetros secundários não é exposta publicamente, nem é incluída nos métodosequals/ geradoshashCode.