Eu estava fazendo o meu caminho através do tutorial Scala playframework e me deparei com este trecho de código que me deixou intrigado:
def newTask = Action { implicit request =>
taskForm.bindFromRequest.fold(
errors => BadRequest(views.html.index(Task.all(), errors)),
label => {
Task.create(label)
Redirect(routes.Application.tasks())
}
)
}
Então decidi investigar e me deparei com este post .
Eu ainda não entendi.
Qual é a diferença entre isso:
implicit def double2Int(d : Double) : Int = d.toInt
e
def double2IntNonImplicit(d : Double) : Int = d.toInt
além do fato óbvio, eles têm nomes de métodos diferentes.
Quando devo usar implicit
e por quê?
scala
syntax
playframework
keyword
Clive
fonte
fonte
Respostas:
Explicarei abaixo os principais casos de uso de implícitos, mas para obter mais detalhes, consulte o capítulo relevante de Programação no Scala .
Parâmetros implícitos
A lista final de parâmetros em um método pode ser marcada
implicit
, o que significa que os valores serão obtidos no contexto em que são chamados. Se não houver valor implícito do tipo certo no escopo, ele não será compilado. Como o valor implícito deve ser resolvido com um único valor e evitar conflitos, é uma boa idéia tornar o tipo específico para sua finalidade, por exemplo, não exija que seus métodos encontrem um implícitoInt
!exemplo:
Conversões implícitas
Quando o compilador encontra uma expressão do tipo errado para o contexto, ele procura um
Function
valor implícito de um tipo que permitirá que ele verifique tipicamente. Portanto, se umA
for necessário e encontrar umB
, ele procurará um valor implícito do tipoB => A
no escopo (ele também verifica alguns outros lugares, como nos objetos complementaresB
eA
, se houver). Uma vez quedef
s pode ser "expandido" emFunction
objetos, o queimplicit def xyz(arg: B): A
será feito também.Portanto, a diferença entre seus métodos é que o marcado
implicit
será inserido pelo compilador quando umDouble
for encontrado, mas umInt
for necessário.funcionará da mesma maneira que
No segundo, inserimos a conversão manualmente; no primeiro, o compilador fez o mesmo automaticamente. A conversão é necessária devido à anotação de tipo no lado esquerdo.
Em relação ao seu primeiro trecho do Google Play:
As ações são explicadas nesta página na documentação do Play (consulte também os documentos da API ). Você está usando
no
Action
objeto (que é o companheiro da característica de mesmo nome).Portanto, precisamos fornecer uma função como argumento, que pode ser escrito como literal na forma
Em uma literal de função, a parte anterior a
=>
é uma declaração de valor e pode ser marcadaimplicit
se você desejar, como em qualquer outraval
declaração. Aqui,request
não precisa ser marcadoimplicit
para que isso digite check, mas, ao fazer isso, estará disponível como um valor implícito para qualquer método que possa ser necessário na função (e, é claro, também pode ser usado explicitamente) . Nesse caso específico, isso foi feito porque obindFromRequest
método na classe Form requer umRequest
argumento implícito .fonte
AVISO: contém sarcasmo criteriosamente! YMMV ...
A resposta de Luigi está completa e correta. Este é apenas para estendê-lo um pouco, com um exemplo de como você pode usar de forma gloriosa o uso implícito , como acontece com frequência nos projetos Scala. Na verdade, com tanta frequência, você provavelmente pode encontrá-lo em um dos guias de "Melhores práticas" .
fonte
Por que e quando você deve marcar o
request
parâmetro comoimplicit
:Alguns métodos que você utilizará no corpo de sua ação têm uma lista implícita de parâmetros como, por exemplo, Form.scala define um método:
Você não percebe isso necessariamente, como chamaria
myForm.bindFromRequest()
Você não precisa fornecer os argumentos implícitos explicitamente. Não, você deixa o compilador para procurar qualquer objeto candidato válido a ser transmitido sempre que encontrar uma chamada de método que exija uma instância da solicitação. Desde que você faz tem um pedido disponível, tudo que você precisa fazer é para marcá-lo comoimplicit
.Você o marca explicitamente como disponível para implícito uso .
Você sugere ao compilador que está "OK" usar o objeto de solicitação enviado pela estrutura do Play (que denominamos "request", mas que poderia ter usado apenas "r" ou "req") sempre que necessário "às escondidas" .
Veja? não está lá, mas é lá!
Isso acontece sem que você precise encaixá-lo manualmente em todos os lugares necessários (mas você pode transmiti-lo explicitamente, se desejar, não importa se está marcado
implicit
ou não):Sem marcar como implícito, você teria que fazer o acima. Marcando-o como implícito, você não precisa.
Quando você deve marcar a solicitação como
implicit
? Você realmente precisa apenas se estiver usando métodos que declarem uma lista implícita de parâmetros esperando uma instância da Solicitação . Mas, para simplificar, você pode adquirir o hábito de marcarimplicit
sempre a solicitação . Dessa forma, você pode simplesmente escrever um belo código conciso.fonte
Em scala, o implícito funciona como :
Conversor
Injetor de valor de parâmetro
Existem 3 tipos de uso do Implicit
Conversão implícita de tipos : converte o erro na produção da atribuição no tipo pretendido
val x: String = "1"
val y: Int = x
String não é o subtipo de Int , portanto, o erro ocorre na linha 2. Para resolver o erro, o compilador procurará um método no escopo que tenha uma palavra-chave implícita e use uma String como argumento e retorne um Int .
tão
Conversão implícita no receptor : Geralmente, pelo receptor chamamos as propriedades do objeto, por exemplo. métodos ou variáveis. Portanto, para chamar qualquer propriedade por um receptor, a propriedade deve ser o membro da classe / objeto desse receptor.
Aqui mahadi.haveTv produzirá um erro. Porque compilador scala procurará primeiro para o haveTv propriedade para Mahadi receptor. Não vai encontrar. Segundo, procurará um método no escopo que possua uma palavra-chave implícita que tome o objeto Mahadi como argumento e retorne o objeto Johnny . Mas não tem aqui. Então, isso criará erro . Mas o seguinte está bem.
Injeção implícita de parâmetros : se chamarmos um método e não passarmos seu valor, isso causará um erro. O compilador scala funciona assim - primeiro tentará passar valor, mas não obterá valor direto para o parâmetro.
Em segundo lugar, se o parâmetro tem qualquer palavra-chave implícita ele vai olhar para qualquer val no âmbito que têm o mesmo tipo de valor. Caso contrário, causará erro.
Para reduzir esse problema, o compilador procurará um valor implícito com o tipo de Int, porque o parâmetro a possui uma palavra-chave implícita .
Outro exemplo:
também podemos escrever como-
Porque eu possui um parâmetro implícito e no escopo do corpo do método x , existe uma variável local implícita ( parâmetros são variáveis locais ) a que é o parâmetro de x , portanto, no corpo do método x , o valor implícito do argumento da assinatura do método l é arquivado pela variável implícita local do método x (parâmetro)
a
implicitamente .assim
estará no compilador como este
Outro exemplo:
causará erro, porque c em x {x => c} precisa passar explicitamente o valor ou argumento implícito no escopo .
Assim, podemos fazer a função do literal parâmetro explicitamente implícita quando chamamos os métodos x
Isso foi usado no método de ação do Play-Framework
se você não mencionar o parâmetro request como implícito explicitamente, deverá ter sido escrito-
fonte
Além disso, no caso acima, deve haver
only one
função implícita cujo tipo édouble => Int
. Caso contrário, o compilador ficará confuso e não será compilado corretamente.fonte
Um exemplo muito básico de implícitos em scala.
Parâmetros implícitos :
Nota: Aqui
multiplier
será implicitamente passado para a funçãomultiply
. Os parâmetros ausentes na chamada de função são pesquisados por tipo no escopo atual, o que significa que o código não será compilado se não houver variável implícita do tipo Int no escopo.Conversões implícitas :
Nota: Quando chamamos a
multiply
função que passa um valor duplo, o compilador tenta encontrar a função implícita de conversão no escopo atual, que é convertidaInt
emDouble
(como parâmetro demultiply
aceitação da funçãoInt
). Se não houverconvert
função implícita , o compilador não compilará o código.fonte
Eu tinha exatamente a mesma pergunta que você e acho que devo compartilhar como comecei a entendê-lo com alguns exemplos realmente simples (observe que ele cobre apenas os casos de uso comuns).
Existem dois casos de uso comuns no Scala usando
implicit
.Exemplos são os seguintes
Utilizando-o em uma variável . Como você pode ver, se a
implicit
palavra-chave for usada na última lista de parâmetros, a variável mais próxima será usada.Utilizando-o em uma função . Como você pode ver, se o
implicit
for usado na função, será usado o método de conversão de tipo mais próximo.Espero que isso possa ajudar.
fonte