隐式的用途是什么?如何在scala中使用隐式?
对于来自Java和其他语言(如隐式的用途是什么?如何在scala中使用隐式?,scala,implicit,Scala,Implicit,对于来自Java和其他语言(如C和C++)的程序员来说,implicit关键字是非常模糊的,因此了解Scala中的implicit关键字非常重要。在Scala中如何使用隐式 许多人可能会发现它是其他帖子的翻版,但事实并非如此。它是 不一样 编辑:: 大多数情况下,问题“隐式在Scala中的用法是什么?”的答案是“如何编写/使用隐式转换?”、“如何使用隐式类型类?”等等 对于新的Scala程序员(至少是我认识的那些),这样的回答大多数时候都会给人一种印象,即隐式的实际上只是一种“美化”工具,可以减
C
和C++
)的程序员来说,implicit
关键字是非常模糊的,因此了解Scala中的implicit
关键字非常重要。在Scala中如何使用隐式
许多人可能会发现它是其他帖子的翻版,但事实并非如此。它是
不一样
编辑::
大多数情况下,问题“隐式在Scala中的用法是什么?”的答案是“如何编写/使用隐式转换?”、“如何使用隐式类型类?”等等
对于新的Scala程序员(至少是我认识的那些),这样的回答大多数时候都会给人一种印象,即隐式的实际上只是一种“美化”工具,可以减少以下内容:
val s = (new RichInt(5)).toString + ":: Well"
公正
val s = 5 + ":: Well"
大多数人只是把隐式看作是一种缩短工具,如果需要的话,他们总是可以避免使用它
一些具有更“裸机”哲学的程序员甚至不喜欢隐式的的存在,因为隐式的隐藏了这些细节
不知何故,“在Scala中,隐含的
的“用途和重要性”是什么?”这一重要问题不知何故被忽视了,也没有得到回答
特别是对Scala非常了解的程序员,他们在某种程度上理解了“如何使用隐式
”,并且有时会被“隐藏的魔法”所困扰,他们想知道这样一个问题:“隐式有什么特别之处,Scala创建者甚至选择了隐式
?”
我不确定OP作为Scala程序员在探索隐含的时是否也考虑了这些问题
令人惊讶的是,我还没有在任何地方找到这些问题的答案。一个原因是,对于隐含的的实际“需要/好处”,即使回答一个用例,也需要大量的解释
我认为这些问题值得社区关注,以帮助新的Scala程序员。我试图简单地解释隐式
的一个用例。我希望看到更多的人(知识更渊博的人)对回答这个问题感兴趣
我回答这个问题更多的是从“隐式的用途是什么”(为什么在某些情况下需要隐式)的角度出发,而不是从“在某些情况下如何使用隐式”的角度出发(在谷歌上搜索可以找到答案)
在解释的过程中,我不知何故在某些地方以一种可互换的方式使用了type
和class
。它仍然应该以简单的方式传达预期的信息,但它可能会向错误的概念表明类型
和类
是相似的。我看不出一种方法可以在不对答案进行重大修改的情况下解决这个问题。请记住,type
和class
不是一回事
什么是隐含的
实际做的。
它实际上非常简单,隐式
正是这个名字所暗示的。如果需要查找所述类型的“转到”实例,它会在相应的范围中将事物标记为“转到”实例/值
因此,我们可以说,类型A
的隐式实例/值是类型A
的“转到”实例,只要需要类型A
的“转到”实例
要将任何实例/值隐式标记为相应范围内可用的(“转到”),我们需要使用隐式关键字
scala> implicit val i: Int = 5
// i: Int = 5
我们如何在需要时调用隐式实例/值?
调用隐式
最直接的方法是使用隐式
方法
val gotoInt = implicitly[Int]
// gotoInt: Int = 5
或者,我们可以使用隐式
参数定义方法
,以期望隐式
实例在其使用范围内的可用性
def addWithImplictInt(i: Int)(implicit j: Int): Int = i + j
请记住,我们也可以在不指定implicit
参数的情况下定义相同的方法
def addWithImplicitInt(i: Int): Int = {
val implictInt = implicitly[Int]
i + implictInt
}
请注意,implicit
参数的第一个选项向用户表明,方法
需要隐式参数。由于这个原因,在大多数情况下应选择隐式
参数(例外情况总是存在)
我们为什么实际使用隐式?
这与我们使用隐式
值的可能方式有些不同。我们正在讨论为什么我们“实际上”需要使用它们
答案是帮助编译器确定类型
,并帮助我们编写类型安全代码,以解决可能导致运行时类型比较的问题,最终我们失去了编译器可以提供给我们的所有帮助
考虑下面的例子
假设我们使用的库定义了以下类型:
trait LibTrait
case class LibClass1(s: String) extends LibTrait
case class LibClass2(s: String) extends LibTrait
case class LibClass3(s: String) extends LibTrait
case class LibClass4(s: String) extends LibTrait
考虑到这是一个开放的trait
,您和其他任何人都可以定义自己的类来扩展这个LibTrait
case class YourClass1(s: String) extends LibTrait
case class YourClass2(s: String) extends LibTrait
case class OthersClass1(s: String) extends LibTrait
case class OthersClass2(s: String) extends LibTrait
现在,我们想定义一个方法
,它只适用于LibTrait
的一些实现(只有那些具有某些特定属性的方法才能执行您需要的特殊行为)
现在,只有支持这种特定行为的LibTrait
的子类型才能实现MyRestriction
现在,用最简单的方式,你用这个定义你的方法
// impl_2
def performMySpecialBehaviour(mr: MyRestriction): Unit
因此,现在用户首先必须将其实例
转换为MyRestriction
的一些实现
(这将确保满足您的限制)
但是看看签名
trait MyRestriction[A <: LibTrait] {
def myRestrictedBehaviour(a: A): Unit
}
// impl_2
def performMySpecialBehaviour(mr: MyRestriction): Unit
// impl_3
def performMySpecialBehaviour[A <: LibTrait](a: A, mr: MyRestriction[A]): Unit
object myRestrictionForYourClass1 extends MyRestriction[YourClass1] {
def myRestrictedBehaviour(a: A): Unit = ???
}
// impl_4
def performMySpecialBehaviour[A :< LibTrait](a: A)(implicit ev: MyRestriction[A]): Unit
trait YoutTrait extends LibTrait
case class YourTraitClass1(s: String) extends YoutTrait
case class YourTraitClass2(s: String) extends YoutTrait
case class YourTraitClass3(s: String) extends YoutTrait
case class YourTraitClass4(s: String) extends YoutTrait
object myRestrictionForYourTraitClass1 extends MyRestriction[YourTraitClass1] {...}
object myRestrictionForYourTraitClass2 extends MyRestriction[YourTraitClass1] {...}
...
...
def otherMethod[A <: YoutTrait](a: A): Unit = {
// do something before
val mr: MyRestriction[A] = ??????????
performMySpecialBehaviour(a, mr)
// do something after
}
def otherMethod[A <: YoutTrait](a: A)(implicit ev: MyRestriction[A]): Unit = {
// do something before
performMySpecialBehaviour(a)
// do something after
}
def restricted[A, B](a: A)(implicit ev: TypeClass[A]): B
def restricted[A: TypeClass, B](a: A): B