Почему неявный параметр не работает в сочетании с неявным параметром - PullRequest
3 голосов
/ 31 января 2020

Очень простой случай использования, скажем, у меня есть класс Foo, который принимает 2 параметра, 1 является нормальным параметром, а 1 - неявным.

class Foo(val msg: String, implicit val n: Int) {
  def multiplier = msg * n
}

implicit val num: Int = 4
val foo = new Foo("yo")
println(foo.msg)

Я знаю, что это сработает, если я переместу неявный параметр в другой список, т.е. curry class Foo(val msg: String)(implicit val n: Int). Но допустим, по какой-то причине я не хочу этого делать.

Может кто-нибудь объяснить, почему текущая версия реализации не работает?

Ответы [ 2 ]

6 голосов
/ 31 января 2020

Спецификация языка написана таким образом. Вы должны определить в отдельном списке параметров. Спецификация языка вообще не говорит о неявных параметрах, а только о списке неявных параметров:

Scala spe c:

An список неявных параметров (implicit p1,…,pn) метода помечает параметры p1,…, pn как неявные. У метода или конструктора может быть только один неявный список параметров, и это должен быть последний заданный список параметров.

Может быть возможно проверить, есть ли какая-либо причина в архивах списков рассылки или в других местах.

1 голос
/ 31 января 2020

Мы не можем смешивать неявные и неявные формальные параметры в списке параметров single , поскольку модификатор implicit является свойством списка , а не параметр. Следовательно, следующее определение метода является недопустимым

def foo(msg: String, implicit n: Int) = ???      // Error

, однако, почему тогда следующее допустимое

class Foo(val msg: String, implicit val n: Int)  // OK

Здесь представляется допустимым смешивать неявные и неявные параметры в одном параметре предложение при объявлении конструктора класса, однако модификатор implicit действительно не применяется к формальному параметру n, а вместо этого изменяет соответствующий автоматически созданный метод доступа member . Поскольку мы объявили n равным val, это расширяется до чего-то вроде

 class Foo {
   ...
   implicit def n(): Int = n;
   def <init>(msg: String, n: Int) = { // note how msg and n are *NOT* implicit
     ...
   }
 }

, и совершенно законно объявить члена неявным. С другой стороны, если мы отбрасываем объявление val, таким образом, не объявляя элемент, мы видим, что он не компилируется

class Foo(val msg: String, implicit n: Int) // Error: 'val' expected but identifier found                                   ^

подобно тому, как это недопустимо в определении метода. Поэтому причина, по которой следующее не компилируется

implicit val num: Int = 4
new Foo("yo") // error: unspecified value parameter n

, заключается в том, что формальный параметр n на самом деле не неявный.


Как сторона обратите внимание, что следующее Scala 2 требование

У метода или конструктора может быть только один неявный список параметров, и это должен быть последний заданный список параметров.

имеет было изменено Scala 3 Несколько заданных предложений

Может быть несколько заданных предложений параметров в определении, а заданные предложения параметров могут быть свободно смешивается с нормальными . Пример:

def f(u: Universe)(given ctx: u.Context)(given s: ctx.Symbol, k: ctx.Kind) = ... 

, где given соответствует implicit.

...