为什么隐式参数与非隐式参数结合时不起作用

Why implicit parameter not working when combined with non implicit parameter

一个非常简单的用例,假设我有一个 class 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)

我知道如果我将隐式参数移动到另一个列表即 curried class Foo(val msg: String)(implicit val n: Int) 它将起作用。但是可以说出于某种原因我不想那样做。

有人可以解释为什么当前版本的实现不起作用吗?

语言规范是这样写的。您必须在单独的参数列表中定义。语言规范根本不讲隐式参数,只讲一个隐式参数列表:

Scala spec:

An implicit parameter list (implicit p1,…,pn) of a method marks the parameters p1,…,pn as implicit. A method or constructor can have only one implicit parameter list, and it must be the last parameter list given.

也许可以在邮件列表存档或其他地方检查是否存在某种原因。

我们cannot mix implicit and non-implicit formal parameters within a single parameter list because implicit modifier is a property of the list,不是参数。因此下面的方法定义是非法的

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

然而为什么以下是合法的

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

在声明 class 构造函数时,在单个参数子句中混合隐式和非隐式参数似乎是合法的,但是 implicit 修饰符 应用于形式参数 n 但它正在修改相应的自动生成的访问器 。因为我们已经声明 nval 这扩展为

 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 要求

A method or constructor can have only one implicit parameter list, and it must be the last parameter list given.

已被 Scala 3 改变Multiple Given Clauses

There can be several given parameter clauses in a definition and given parameter clauses can be freely mixed with normal ones. Example:

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

其中 given implicit.