Scala中隐式参数的好例子?

Scala中隐式参数的好例子?,scala,parameters,implicit,Scala,Parameters,Implicit,到目前为止,Scala中的隐式参数对我来说并不合适——它太接近全局变量,然而,由于Scala似乎是一种相当严格的语言,我开始怀疑自己的观点:-) 问题:当隐式参数真正起作用时,您能给出一个真实(或接近)的好例子吗。IOW:比showPrompt更严重的东西,这将证明这样的语言设计是合理的 或者相反——你能展示出可靠的语言设计(可以是虚构的)让隐式语言变得不必要吗。我认为,甚至没有任何机制比隐式更好,因为代码更清晰,没有猜测 请注意,我问的是参数,不是隐式函数(转换) 更新 全局变量 谢谢你的回答

到目前为止,Scala中的隐式参数对我来说并不合适——它太接近全局变量,然而,由于Scala似乎是一种相当严格的语言,我开始怀疑自己的观点:-)

问题:当隐式参数真正起作用时,您能给出一个真实(或接近)的好例子吗。IOW:比showPrompt更严重的东西,这将证明这样的语言设计是合理的

或者相反——你能展示出可靠的语言设计(可以是虚构的)让隐式语言变得不必要吗。我认为,甚至没有任何机制比隐式更好,因为代码更清晰,没有猜测

请注意,我问的是参数,不是隐式函数(转换)

更新 全局变量 谢谢你的回答。也许我要澄清我的“全局变量”反对意见。考虑这样的函数:

max(x : Int,y : Int) : Int
你管它叫什么

max(5,6);
你可以这样做:

max(x:5,y:6);
x = 5;
y = 6;
max()
trait ScalaActorRef { this: ActorRef =>
  ...

  def !(message: Any)(implicit sender: ActorRef = null): Unit

  ...
}
someOtherActor ! SomeMessage
def max[T <% Ordered[T]](a: T, b: T): T = if (a < b) b else a
def max[T](a: T, b: T)(implicit $ev1: Function1[T, Ordered[T]]): T = if ($ev1(a) < b) b else a
def f[T: ClassManifest](size: Int) = new Array[T](size)
withTransaction { implicit txn =>
  op1(data)
  op2(data)
  op3(data)
}
但在我看来,
的含义是这样的:

max(x:5,y:6);
x = 5;
y = 6;
max()
trait ScalaActorRef { this: ActorRef =>
  ...

  def !(message: Any)(implicit sender: ActorRef = null): Unit

  ...
}
someOtherActor ! SomeMessage
def max[T <% Ordered[T]](a: T, b: T): T = if (a < b) b else a
def max[T](a: T, b: T)(implicit $ev1: Function1[T, Ordered[T]]): T = if ($ev1(a) < b) b else a
def f[T: ClassManifest](size: Int) = new Array[T](size)
withTransaction { implicit txn =>
  op1(data)
  op2(data)
  op3(data)
}
它与这种构造(类似于PHP)没有太大区别

德里克的回答
这是一个很好的例子,但是,如果你可以认为发送消息是一种灵活的用法,而不是使用
隐式
,请给出一个反例。我真的很好奇语言设计的纯洁性;-)

在集合API中大量使用隐式参数。许多函数都会获得隐式的CanBuildFrom,从而确保获得“最佳”结果集合实现


如果没有隐式,您可能会一直传递这样的东西,这会使正常使用变得麻烦。或者使用不太专业的集合,这会让人恼火,因为这意味着你会失去性能/电源。

当然。Akka在演员方面有一个很好的例子。当您在参与者的
receive
方法中时,您可能希望向另一个参与者发送消息。执行此操作时,Akka将绑定(默认情况下)当前参与者作为消息的
发送者,如下所示:

max(x:5,y:6);
x = 5;
y = 6;
max()
trait ScalaActorRef { this: ActorRef =>
  ...

  def !(message: Any)(implicit sender: ActorRef = null): Unit

  ...
}
someOtherActor ! SomeMessage
def max[T <% Ordered[T]](a: T, b: T): T = if (a < b) b else a
def max[T](a: T, b: T)(implicit $ev1: Function1[T, Ordered[T]]): T = if ($ev1(a) < b) b else a
def f[T: ClassManifest](size: Int) = new Array[T](size)
withTransaction { implicit txn =>
  op1(data)
  op2(data)
  op3(data)
}
发送方是隐式的。在Actor中,有一个定义如下:

trait Actor {
  ...

  implicit val self = context.self

  ...
}
这将在您自己的代码范围内创建隐式值,并允许您执行以下简单操作:

max(x:5,y:6);
x = 5;
y = 6;
max()
trait ScalaActorRef { this: ActorRef =>
  ...

  def !(message: Any)(implicit sender: ActorRef = null): Unit

  ...
}
someOtherActor ! SomeMessage
def max[T <% Ordered[T]](a: T, b: T): T = if (a < b) b else a
def max[T](a: T, b: T)(implicit $ev1: Function1[T, Ordered[T]]): T = if ($ev1(a) < b) b else a
def f[T: ClassManifest](size: Int) = new Array[T](size)
withTransaction { implicit txn =>
  op1(data)
  op2(data)
  op3(data)
}
现在,如果您愿意,也可以这样做:

someOtherActor.!(SomeMessage)(self)


但通常你不会。您只需保留Actor trait中的隐式值定义所允许的自然用法。还有大约一百万个其他的例子。收集类是一个庞大的类。尝试在任何一个非平凡的Scala库中漫游,你会发现一大堆。隐式参数的另一个很好的通用用法是使方法的返回类型取决于传递给它的某些参数的类型。Jens提到的一个很好的例子是collections框架和方法,如
map
,其完整签名通常是:

def map[B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom[GenSeq[A], B, That]): That
请注意,
的返回类型
由编译器可以找到的最佳拟合
CanBuildFrom
确定


有关这方面的另一个示例,请参见。在这里,根据某个隐式参数类型(
BiConverter
)确定方法
算术.apply的返回类型。

一个例子是对
可遍历[a]
的比较操作。例如
max
sort

def max[B >: A](implicit cmp: Ordering[B]) : A

只有当有一个操作
在某种意义上,是的,它隐式地表示全局状态时,才能合理地定义这些操作。然而,它们是不可变的,这是全局变量的真正问题——你没有看到人们抱怨全局常量,是吗?事实上,编码标准通常要求您将代码中的任何常量转换为常量或枚举,这些常量或枚举通常是全局的

还要注意隐式不在平面名称空间中,这也是全局的一个常见问题。它们显式地绑定到类型,因此绑定到这些类型的包层次结构

因此,使用您的全局变量,使它们不可变并在声明站点初始化,然后将它们放在名称空间中。他们看起来还像地球人吗?他们看起来仍然有问题吗

但我们不要就此止步。隐式与类型相关,它们与类型一样具有“全局性”。类型是全局的这一事实是否会困扰您


至于用例,它们有很多,但是我们可以根据它们的历史做一个简短的回顾。起初,阿福,斯卡拉并没有含蓄。Scala所拥有的是视图类型,这是许多其他语言所拥有的特性。我们仍然可以看到,今天无论你写什么东西,比如
T都很容易,只要记住:

  • 将要传入的变量声明为隐式
  • 在单独的()中声明非隐式参数之后的所有隐式参数
e、 g


根据我的经验,使用隐式ITS参数或隐式ITS转换没有真正好的例子

使用隐式(不需要显式地编写参数或类型)的小好处与它们所造成的问题相比是多余的

我做了15年的开发人员,在过去的1.5年里一直在scala工作

我见过很多次错误,这些错误是由于开发人员不知道使用了隐式函数,并且特定函数实际上返回了与指定函数不同的类型。由于隐式转换

我还听到有人说,如果你不喜欢含蓄,就不要使用它们。 这在现实世界中并不实用,因为很多时候都使用外部库,而且很多库都使用隐式,所以您的代码使用隐式,而您可能没有意识到这一点。 您可以编写具有以下任一项的代码:

import org.some.common.library.{TypeA, TypeB}
或:

这两个代码都将编译并运行。 但它们并不总是产生相同的结果,因为第二个版本导入了它的转换,这将使代码表现出不同的行为

由此引起的“bug”可能会在虚拟企业中发生