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

问题描述 投票:2回答:2

[一个非常简单的用例,假设我有一个接受2个参数的类Foo,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)

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

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

scala implicit
2个回答
6
投票

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

Scala spec

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

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

0
投票
它不起作用的原因是因为

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

我们实际上不是在声明类

constructor parameter n是隐式的,相反,我们是在声明相应的类member是隐式的。因为我们已经声明nval,所以它扩展为类似

class Foo { ... implicit def n(): Int = n; private[this] val n: Int = _; 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 ^

类似于在方法定义中如何非法

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


作为补充,以下Scala 2要求

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

已由Scala 3 Multiple Given Clauses放宽

在定义中可以有

几个个给定的参数子句,给定的参数子句可以与普通子句自由混合。示例:

def f(u: Universe)(given ctx: u.Context)(given s: ctx.Symbol, k: ctx.Kind) = ...
其中given correspondsimplicit
© www.soinside.com 2019 - 2024. All rights reserved.