【问题标题】:What's the point of implicit conversions as parameters?隐式转换作为参数有什么意义?
【发布时间】:2020-07-24 10:43:20
【问题描述】:

我正在阅读docs on implicits in Scala,并且有一个以隐式转换为参数的函数示例:

def getIndex[T, CC](seq: CC, value: T)(implicit conv: CC => Seq[T]) = seq.indexOf(value)

我明白它是如何工作的,但我不明白这样写的意义何在:

def getIndexExplicit[T](seq: Seq[T], value: T) = seq.indexOf(value)

据我所知,如果从参数seq 到类型Seq[T] 的转换存在,编译器仍然允许调用getIndexExplicit

为了说明我的观点,我准备了这个简单的例子:

def equal42[T](a: T)(implicit conv: T => Int) = conv(a) == 42  // implicit parameter version
def equal42Explicit(a: Int) = a == 42                          // just use the type in the signature

implicit def strToInt(str: String): Int = java.lang.Integer.parseInt(str) // define the implicit conversion from String to Int

事实上,这两个函数似乎以相同的方式工作:

scala> equal42("42")
res12: Boolean = true

scala> equal42Explicit("42")
res13: Boolean = true

如果没有区别,显式定义隐式转换有什么意义?

我的猜测是,在这种简单的情况下,它没有任何区别,但肯定有一些更复杂的情况。那些是什么?

【问题讨论】:

  • 当然你的例子没有意义,因为你的函数已经需要一个Int 试试equal42Explicit[T](t: T): Boolean = t == 42 - 这个想法很简单,你得到了转换,所以你可以显式使用它或让它隐式传递到堆栈中,甚至根本不使用它。此外,第一个允许调用者根据需要显式传递它。
  • 然后equal42Explicit("42") 返回false!这是为什么呢?
  • 它作为 String 传递,而 String 总是不同于 Int。这是 Java 使用的 普遍相等 以及 Scala 的问题。
  • 啊,当然。谢谢!

标签: scala implicit-conversion implicit implicit-typing


【解决方案1】:

在您的超级简单示例中:

equal42("42")
equal42Explicit("42")

等于

equal42("42")(strToInt)
equal42Explicit(strToInt("42"))

如果你的定义没有区别。

但是如果它做了其他事情,例如

def parseCombined[S, T](s1: S, s2: S)
                       (combine: (S, S) => S)
                       (implicit parse: S => Option[T]): Option[T] =
  parse(combine(s1, s2))

那么何时应用转换很重要:

implicit def lift[T]: T => Option[T] = t => Option(t)
implicit val parseInt: String => Option[Int] = s => scala.util.Try(s.toInt).toOption
implicit def parseToString[T]: T => Option[String] = t => Option(t.toString)
parseCombined[Option[Int], String]("1", "2") { (a, b) => a.zip(b).map { case (x, y) => x + y } } // Some("Some(3)")
parseCombined[String, Int]("1", "2") { _ + _ } //  Some(12)

在第一种情况下,参数在传递之前被转换(然后在内部),而在另一种情况下,它们仅在特定位置的函数内部进行转换。

虽然这个案例有些牵强,但它表明控制何时进行转换可能对最终结果很重要。

话虽如此,隐式转换的这种用法是一种反模式,类型类会更好地为它工作。实际上,扩展方法是隐式转换唯一没有争议的用法,因为即使是磁铁模式——可能在生产中使用的唯一其他用例(参见 Akka)——也可能被视为问题。

因此,请将此文档中的示例视为一种机制的演示,而不是应在生产中使用的良好实践示例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-08-03
    • 2016-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-11
    • 2013-01-26
    相关资源
    最近更新 更多