我应该如何在Scala应用程序中组织implicits?

时间:2009-08-13 02:56:41

标签: scala

编写了一些scala工具后,我正试图掌握安排代码的最佳方法 - 特别是暗示。我有2个目标:

  • 有时候,我希望能够只导入我要求的含义。
  • Othertimes,我想导入一切。

为了避免重复隐含,我提出了这种结构(类似于scalaz的排列方式):

case class StringW(s : String) {
  def contrived = s + "?"
}

trait StringWImplicits {
  implicit def To(s : String) = StringW(s)
  implicit def From(sw : StringW) = sw.s
}

object StringW extends StringWImplicits

// Elsewhere on Monkey Island

object World extends StringWImplicits with ListWImplicits with MoreImplicits

这让我只是

import StringW._ // Selective import

或(在大多数情况下)

import World._. // Import everything

其他人如何做到这一点?

2 个答案:

答案 0 :(得分:4)

如果您不知道他们来自哪里,我认为implicit次转化很危险。在我的情况下,我将implicit放在Conversions课程中,import 尽可能接近使用

def someMethod(d: Date) ; Unit {
  import mydate.Conversions._
  val tz = TimeZone.getDefault 
  val timeOfDay = d.getTimeOfDay(tz) //implicit used here
  ...
}

我不确定我是否喜欢“继承”来自各种trait的隐含,因为它被认为是糟糕的Java实践来实现interface所以你可以直接使用它的常量(首选静态导入)。

答案 1 :(得分:1)

我通常在一个对象中进行了implicit次转换,这清楚地表明它的导入内容是implicit转换。

例如,如果我有一个类com.foo.bar.FilthyRichString,则隐式转换将进入com.foo.bar.implicit.FilthyRichStringImplicit。我知道这些名称有点长,但这就是为什么我们有IDE(并且Scala IDE支持越来越好)。我这样做的方式是,我认为所有隐式转换都可以在10 second code review中清晰地查看。我可以查看以下代码:


// other imports
import com.foo.bar.FilthyRichString

import com.foo.bar.util.Logger
import com.foo.bar.util.FileIO

import com.foo.bar.implicits.FilthyRichStringImplicit._
import com.foo.bar.implicits.MyListImplicit._
// other implicits

并快速查看此源文件中处于活动状态的所有隐式转换。如果您使用导入按包分组的约定,并且在不同包之间使用新行,它们也会聚集在一起。

沿着相同的参数,我不喜欢包含所有隐式转换的catch-all对象。在一个大项目中,你真的会在所有源文件中使用所有隐式转换吗?我认为这样做意味着代码的不同部分之间的紧密耦合。

此外,一个包罗万象的对象不是很好的文档。在显式写入文件中使用的所有隐式转换的情况下,可以只查看import语句并立即跳转到隐式类的文档。对于catch-all对象,人们必须查看该对象(在大项目中可能很大),然后搜索它们之后的隐式转换。

我同意oxbow_lakes在trait中隐含转换是不好的,因为它继承了它的诱惑,正如他所说的那样,这是不好的做法。沿着这些方向,我会使对象保持隐式转换final只是为了完全避免诱惑。如果隐式转换只是在代码中谨慎使用,那么他将导入它们尽可能接近使用的想法也非常好。

-- Flaviu Cipcigan