Почему вывод типа Scala терпит неудачу здесь? - PullRequest
11 голосов
/ 23 июля 2010

У меня этот класс в Scala:

object Util {
  class Tapper[A](tapMe: A) {
    def tap(f: A => Unit): A = {
      f(tapMe)
      tapMe
    }

    def tap(fs: (A => Unit)*): A = {
      fs.foreach(_(tapMe))
      tapMe
    }
  }

  implicit def tapper[A](toTap: A): Tapper[A] = new Tapper(toTap)
}

Теперь

"aaa".tap(_.trim)

не компилируется, выдавая ошибку

ошибка: отсутствует тип параметра для расширенной функции ((x $ 1) => x $ 1.trim)

Почему тип не выводится как String?Из ошибки кажется, что неявное преобразование срабатывает (в противном случае ошибка будет выглядеть так: «tap не является членом класса String»).И, похоже, преобразование должно быть Tapper[String], что означает, что тип аргумента String => Unit (или (String => Unit)*).

Интересно то, что если я закомментирую либо из tap определений, затем он компилируется.

1 Ответ

17 голосов
/ 23 июля 2010

6.26.3 Разрешение перегрузки

Сначала определяется набор потенциально применимых функций на основе формы аргументов

...

Если в B есть только одна альтернатива, эта альтернатива выбирается.

В противном случае, пусть S1,.,,Sm - вектор типов, полученный путем ввода каждого аргумента с неопределенным ожидаемым типом.

Потенциально применимы обе перегрузки tap (основанные на «форме» аргументов, которая учитываетконструкторы arity и type FunctionN).

Таким образом, типер работает так же, как и при:

val x = _.trim

, и завершается неудачей.

Более умный алгоритм может принимать наименьшую верхнюю границусоответствующего типа параметра каждой альтернативы, и используйте его как ожидаемый тип.Но эта сложность не стоит того, ИМО.Перегрузка имеет много угловых случаев, это всего лишь другое.

Но в этом случае вы можете воспользоваться трюком, если вам действительно нужна перегрузка, которая принимает один параметр:

object Util {
  class Tapper[A](tapMe: A) {
    def tap(f: A => Unit): A = {
      f(tapMe)
      tapMe
    }

    def tap(f0: A => Unit, f1: A => Unit, fs: (A => Unit)*): A = {
      (Seq(f0, f1) ++ fs).foreach(_(tapMe))
      tapMe
    }
  }

  implicit def tapper[A](toTap: A): Tapper[A] = new Tapper(toTap)

  "".tap(_.toString)
  "".tap(_.toString, _.toString)
  "".tap(_.toString, _.toString, _.toString)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...