3

一个非常简单的用例,假设我有一个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)。但可以说出于某种原因我不想这样做。

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

4

2 回答 2

6

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

斯卡拉规范

方法的隐式参数列表 将参数…(implicit p1,…,pn)标记为隐式。一个方法或构造函数只能有一个隐式参数列表,并且它必须是给定的最后一个参数列表。p1pn

可以在邮件列表档案或其他地方检查是否有某些原因。

于 2020-01-31T07:57:24.190 回答
2

我们不能在单个参数列表中混合隐式和非隐式形式参数,因为implicit修饰符是列表的属性,而不是参数。因此下面的方法定义是非法的

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

但是为什么以下是合法的

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

在这里,在声明类构造函数时,在单个参数子句中混合隐式和非隐式参数似乎是合法的,但是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 要求

一个方法或构造函数只能有一个隐式参数列表,并且它必须是给定的最后一个参数列表。

已被 Scala 3 Multiple Given Clauses更改

一个定义中可以有多个给定的参数子句,并且给定的参数子句可以与正常的参数子句自由混合。例子:

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

given 对应于哪里implicit

于 2020-01-31T19:05:27.100 回答