Como '20 segundos 'funcionam no Scala?

130

Como o seguinte compila:

import scala.concurrent.duration._

val time = 20 seconds

O que realmente está acontecendo aqui?

ripper234
fonte

Respostas:

171

Há algumas coisas acontecendo.

Primeiro, Scala permite que pontos e parênteses sejam omitidos em muitas chamadas de método, portanto 20 secondsé equivalente a 20.seconds()*.

Segundo, uma "conversão implícita" é aplicada. Como 20é um método Inte Intnão possui secondsmétodo, o compilador procura por uma conversão implícita que recebe Inte retorna algo que possui um secondsmétodo, com a pesquisa restrita pelo escopo da sua chamada de método.

Você importou DurationInt para seu escopo. Como DurationInté uma classe implícita com um Intparâmetro, seu construtor define uma Int => DurationIntconversão implícita . DurationIntpossui um secondsmétodo, portanto, atende a todos os critérios de pesquisa. Portanto, o compilador reescreve sua chamada como new DurationInt(20).seconds**.

* Eu quero dizer isso vagamente. 20.seconds()é realmente inválido porque o secondsmétodo não possui lista de parâmetros e, portanto, os parênteses devem ser omitidos na chamada do método.

** Na verdade, isso não é verdade porque DurationInté uma classe de valor; portanto, o compilador evitará agrupar o número inteiro, se possível.

Aaron Novstrup
fonte
83
Qualquer tecnologia suficientemente avançada é indistinguível da mágica.
Ripper234
4
Felizmente, a maioria dos IDEs é capaz de diferenciá-lo! Conversões implícitas se acostumam bastante no Scala. Se você está apenas lendo o arquivo de texto, pode ser confuso ("de onde vem esse método"), mas com o suporte adequado às ferramentas, você poderá encontrar o caminho, nesse ponto o Scala pode ser lindamente significativo e conciso. (por exemplo, 20.seconds é muito mais legível do que new DurationInt(20).seconds(), desde que você sabe como ele faz isso)
William Billingsley
1
Se você se encontra usando implícitos, sempre se pergunte se existe uma maneira de conseguir a mesma coisa sem a ajuda deles. twitter.github.com/effectivescala/#Types and Generics-Implicits
oluies
4
Na verdade, o secondsmétodo é definido sem parênteses, portanto, chamá-lo com parênteses é um erro.
Frank S. Thomas
1
@ Frank Esse é um bom ponto. Eu não quis sugerir que você possa escrever 20.seconds()em Scala, apenas que o compilador está traduzindo a chamada dessa maneira. Vale ressaltar que o Scala exige que você omita parens se o método correspondente não tiver uma lista de parâmetros, como neste caso.
Aaron Novstrup
7

A "mágica" que está acontecendo lá é chamada de "conversão implícita". Você está importando as conversões implícitas e algumas delas lidam com a conversão entre Int (e Double) em Duration. É com isso que você está lidando.

Bruno Reis
fonte
1
Alguma idéia de por que a importação é import scala.concurrent.duration._resolvida, 20 secondsmas a importação do DurationConversionsTrait não é verdade? EDIT : Acabei de perceber o que eles estão realmente importando DurationInt. Acho que é porque você não pode importar o traço real? Apenas uma implementação concreta do traço?
19418 franklin