【问题标题】:Why prefer implicit val over implicit object为什么更喜欢隐式 val 而不是隐式对象
【发布时间】:2021-03-23 06:45:37
【问题描述】:

当询问有关隐含的常见建议/建议/建议时,与答案一起给出(有时这就是答案本身)是使用implicit valsexcplicit 类型签名而不是使用implicit objects

但是,这背后的原因是什么?

【问题讨论】:

标签: scala design-patterns implicit


【解决方案1】:

"TL;DR;" 原因是具有显式类型签名的 implici val 具有您想要的确切类型,而 implicit object 具有不同的类型。

说明问题原因的最佳方法是举一个简单的例子:

// Having the following definitions.

trait SomeTrait[T] {
  def f: T
}

trait ExtendedTrait[T] extends SomeTrait[T] {
  def g: T
}

implicit val SomeStringVal: SomeTrait[String] = new SomeTrait[String] {
  override def f: String = "from val f"
}

implicit val ExtendedStringVal: ExtendedTrait[String] = new ExtendedTrait[String] {
  override def f: String = "from extended val f"
  override def g: String = "from extended val g"
}

implicit object ExtendedStringObject extends ExtendedTrait[String] {
  override def f: String = "from extended obj f"
  override def g: String = "from extended obj g"
}

// What will be the result of:
implicitly[SomeTrait[String]].f

记住:

如果有多个符合条件的参数与隐式参数的类型匹配,则将使用静态重载决策规则选择最具体的参数。

那么,答案是:"from extended obj f"
上面的(有点意外)的结果,是因为对象有自己的类型(单例类型ExtendedStringObject.typeExtendedTrait[String]的子类型)比其他人更“具体”

现在,这可能是一个问题的原因是大多数人不知道object 有自己的类型,而且它比他们认为的更具体。尽管如此,这也可能使object 在您不希望的时候被选中;例如:

// If instead we only had this:

implicit val ExtendedStringVal: ExtendedTrait[String] = new ExtendedTrait[String] {
  override def f: String = "from extended val f"
  override def g: String = "from extended val g"
}

implicit object ExtendedStringObject extends SomeTrait[String] {
  override def f: String = "from extended obj f"
}

// Then what will be the result of:
implicitly[SomeTrait[String]].f

在这种情况下,我们会有一个“模糊隐含值”异常;因为这两个选项同样特定


规则是否通用?

没有。

与软件工程中的大多数事情一样,没有什么是通用的。
在某些情况下,使用带有显式类型签名的implicit valnot possible (例如,因为即使编译器知道它存在,该类型在源代码中也不可写) 或@987654322 @.
一个简单的例子是:

trait A {
  type X
}

object A {
  type Aux[XX] = A { type X = XX }
}

class B extends A {
  type X = T

  class T
}

implicit object b extends B
implicit object b1 extends B

这样您就可以请求implicitly[A.Aux[b.T]],而使用implicit val b: B = new B {} 将不起作用。
(运行here 完整上下文here 的代码)

但是,可以说这些是罕见的(高级)案例。因此,这可以被认为是一个很好的指导方针。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-30
    • 2015-08-13
    • 1970-01-01
    相关资源
    最近更新 更多