题 为什么隐式defs需要implicitConversions而不是类?


据我所知,隐式转换可能导致可能难以理解的代码,或者代码遭遇其他问题(甚至可能是错误?),这就是为什么它们需要显式启用才能在代码中使用而不会收到警告。

但是,鉴于隐式转换在很大程度上(如果不是大部分时间)用于包装具有另一种类型的对象的对象,因此是隐式类 - 如果我错了,我会感激你纠正我 - 为什么前者要求进口 scala.language.implicitConversions 但后者不?

object Main extends App {
  implicit class StringFoo(x: String) {
    def fooWithImplicitClass(): Unit =
      println("foo with implicit class")
  }
  // => silence.

  "asd".fooWithImplicitClass()

  /************************/

  class Foo(x: String) {
    def fooWithImplicitDef(): Unit =
      println("foo with implicit def")
  }
  implicit def string2Foo(x: String) = new Foo(x)
  // => warning: implicit conversion method string2Foo should be enabled

  "asd".fooWithImplicitDef()
}

31
2017-09-20 10:59


起源




答案:


隐式类有效地仅添加新方法(或特征),并且它们仅在调用这些添加的方法时使用(或者显式使用隐式类,但这在实践中很少发生)。另一方面,对程序员的可见性较低,可以调用对现有类型的隐式转换。


20
2017-09-20 11:19



你是说这是因为隐式转换不仅在使用“原始”类型中不存在的方法时,而且在请求“隐式类型”的对象时,例如,路过的时候 TypeA 代替 TypeB 和转换 TypeA -> TypeB 存在? - Erik Allik
@RégisJean-Gilles:Alexey的意思是 StringFoo 是一种专门用于修改具有额外方法的现有类型的类型,而隐式转换允许从类型转换 A 完全没有关联 B 无 B 是专门为此目的而创建的。 (但我现在仍然看到是否会弹出更好的解释) - Erik Allik
@Erik在REPL中的快速实验表明隐式类执行相同的转换,所以我不理解这个参数 ideone.com/m025gQ - Luigi Plinge
因此,如果我理解正确,这里的论点是隐式转换(在一般意义上)的更大的多功能性(以及更大的风险表面)?如果是这样,可以认为编译器可以(应该?)如果所谓的隐式转换在与它转换为的类相同的范围内定义,则不会发出警告(假设在这种情况下我们处于完全相同的情况)当使用隐式类时)。我想,不加思索地发出警告就更容易了。 - Régis Jean-Gilles
@RégisJean-Gilles我同意在这种情况下不需要发出警告。另一方面,我也认为为扩展其他类实现特征的隐式类发出警告是有意义的,因为它们也是对预先存在的类型的转换。我猜它被忽略了,因为这种隐含的类很少见(我从未见过),但它们是合法的。 - Alexey Romanov


IMO,隐式类和隐式转换之间没有根本区别,因为它们可能会产生混淆,因此两者都应该被警告。

但是通过将类定义为隐式,它就像通过告诉编译器“我是成年人,我知道我在做什么来明确地抑制警告。这个类本打算以这种方式使用(可能作为扩展包装器) “。因此,由于您作为类的创建者明确表示隐式使用此类应该如何工作或如何允许使用类,因此编译器应该信任您,因此不会发出警告。

另一方面,无论是否打算隐式使用目标类,您都可以使用隐式转换将对象转换为任何类。这是许多问题的根源,也是Scala试图阻止的问题。


0
2017-09-14 08:43



该参数的问题在于转换为的类 不 需要被定义为隐含的 或 案件。例如: ideone.com/1wwCoA - aij
但我认为在您提供的代码示例中,该字符串IS已转换为 StringToFoo, 对? ideone.com/sBKryP - Lifu Huang