Как работает «20 секунд» в Scala?

130

Как компилируется следующее:

import scala.concurrent.duration._

val time = 20 seconds

Что на самом деле здесь происходит?

ripper234
источник

Ответы:

171

Происходит несколько вещей.

Во-первых, Scala позволяет опускать точки и скобки во многих вызовах методов, что 20 secondsэквивалентно 20.seconds()*.

Во-вторых, применяется «неявное преобразование». Так как 20это Intи Intне имеет никакого secondsметода, компилятор ищет неявное преобразование , который принимает Intи возвращает то , что действительно есть в secondsметоде, с поиском стесненного рамкой вашего вызова метода.

Вы импортировали DurationInt в свою область видимости. Поскольку DurationIntэто неявный класс с Intпараметром, его конструктор определяет неявное Int => DurationIntпреобразование. DurationIntимеет secondsметод, поэтому он удовлетворяет всем критериям поиска. Поэтому компилятор переписывает ваш вызов как new DurationInt(20).seconds**.

* Я имею в виду это свободно. 20.seconds()фактически недействителен, потому что у secondsметода нет списка параметров, и поэтому скобки при вызове метода должны быть опущены.

** На самом деле это не совсем так, потому что DurationIntэто класс значений, поэтому компилятор по возможности избегает обертывания целого числа.

Аарон Новструп
источник
83
Любая достаточно развитая технология неотличима от магии.
ripper234
4
К счастью, большинство IDE могут это распознать! Неявные преобразования довольно часто используются в Scala. Если вы просто читаете текстовый файл, это может сбить с толку («откуда взялся этот метод»), но при соответствующей поддержке инструментов вы сможете сориентироваться, и в этот момент Scala может быть красиво осмысленным и кратким. (например, 20 секунд гораздо более читабельны, чем new DurationInt(20).seconds()до тех пор, пока вы знаете, как они это делают)
Уильям Биллингсли
1
Если вы обнаружите, что используете имплициты, всегда спрашивайте себя, есть ли способ добиться того же без их помощи. twitter.github.com/effectivescala/#Types and Generics-Implicits
oluies
4
На самом деле secondsметод определяется без скобок, поэтому вызов его с скобками является ошибкой.
Фрэнк С. Томас
1
@Frank Это хороший момент. Я не имел в виду, что вы можете писать 20.seconds()на Scala, я просто хотел сказать , что компилятор переводит вызов таким образом. Стоит отметить, что Scala требует , чтобы вы опускали скобки, если соответствующий метод не имеет списка параметров, как в этом случае.
Аарон Новструп
7

«Магия», которая там происходит, называется «неявным преобразованием». Вы импортируете неявные преобразования, и некоторые из них обрабатывают преобразование между Int (и Double) в Duration. Вот с чем вы имеете дело.

Бруно Рейс
источник
1
Есть идеи, почему импорт import scala.concurrent.duration._разрешает, 20 secondsа на самом деле импорт DurationConversionsTrait - нет? РЕДАКТИРОВАТЬ : только что понял, что они на самом деле импортируют DurationInt. Я предполагаю, что это потому, что вы не можете импортировать настоящую черту? Только конкретная реализация Черты?
Франклин