Jak działa „20 sekund” w Scali?

132

Jak kompiluje się następujący plik:

import scala.concurrent.duration._

val time = 20 seconds

Co tu się właściwie dzieje?

zrywak234
źródło

Odpowiedzi:

173

Dzieje się kilka rzeczy.

Po pierwsze, Scala pozwala na pomijanie kropek i paren w wielu wywołaniach metod, więc 20 secondsjest odpowiednikiem 20.seconds()*.

Po drugie, stosowana jest „niejawna konwersja”. Ponieważ 20jest Inti Intnie ma secondssposobu, kompilator przeszukuje niejawna konwersja, która pobiera Inti zwraca coś, co ma się secondsmetodę, przy poszukiwaniu ograniczony zakresem swojej wywołania metody.

Zaimportowałeś DurationInt do zakresu. Ponieważ DurationIntjest to niejawna klasa z Intparametrem, jej konstruktor definiuje niejawną Int => DurationIntkonwersję. DurationIntma secondsmetodę, więc spełnia wszystkie kryteria wyszukiwania. Dlatego kompilator przepisuje Twoje wywołanie na new DurationInt(20).seconds**.

* Mam na myśli to luźno. 20.seconds()jest faktycznie nieprawidłowy, ponieważ secondsmetoda nie ma listy parametrów i dlatego parametry muszą zostać pominięte w wywołaniu metody.

** Właściwie nie jest to do końca prawdą, ponieważ DurationIntjest to klasa wartości, więc kompilator uniknie zawijania liczby całkowitej, jeśli to możliwe.

Aaron Novstrup
źródło
84
Każda wystarczająco zaawansowana technologia jest nie do odróżnienia od magii.
ripper234
4
Na szczęście większość IDE jest w stanie to rozróżnić! Niejawne konwersje są często używane w Scali. Jeśli czytasz tylko plik tekstowy, może to być mylące („skąd bierze się ta metoda”), ale przy odpowiednim wsparciu narzędzi powinieneś być w stanie znaleźć drogę, w którym to momencie Scala może mieć piękne znaczenie i zwięzłość. (np. 20 sekund jest znacznie bardziej czytelne new DurationInt(20).seconds(), o ile wiesz, jak to robi)
William Billingsley,
1
Jeśli zauważysz, że używasz implikacji, zawsze zadaj sobie pytanie, czy jest sposób na osiągnięcie tego samego bez ich pomocy. twitter.github.com/effectivescala/#Types and Generics-Implicits
oluies
4
W rzeczywistości secondsmetoda jest zdefiniowana bez parenów, więc wywołanie jej z parens jest błędem.
Frank S. Thomas
1
@Frank To dobra uwaga. Nie chciałem sugerować, że możesz pisać 20.seconds()w Scali, tylko że kompilator tłumaczy wywołanie w ten sposób. Warto zauważyć, że Scala wymaga pominięcia parenów, jeśli odpowiednia metoda nie ma listy parametrów, jak w tym przypadku.
Aaron Novstrup
7

„Magia”, która tam się dzieje, nazywa się „niejawną konwersją”. Importujesz niejawne konwersje, a niektóre z nich obsługują konwersję między Int (i Double) na Duration. Z tym właśnie masz do czynienia.

Bruno Reis
źródło
1
Masz jakiś pomysł, dlaczego importowanie import scala.concurrent.duration._rozwiązuje się, 20 secondsale w rzeczywistości importowanie DurationConversionscechy nie? EDYCJA : Właśnie zdałem sobie sprawę, że tak naprawdę importują DurationInt. Zgaduję, że dzieje się tak, ponieważ nie możesz zaimportować rzeczywistej cechy? Tylko konkretna realizacja cechy?
franklin