在 Scala 中捆绑导入

Posted

技术标签:

【中文标题】在 Scala 中捆绑导入【英文标题】:Bundle imports in Scala 【发布时间】:2017-01-16 23:17:11 【问题描述】:

在我的 Scala 项目中,我几乎所有的文件都有这些导入:

import eu.timepit.refined._
import eu.timepit.refined.api.Refined
import eu.timepit.refined.auto._
import eu.timepit.refined.numeric._

import spire.math._
import spire.implicits._

import com.wix.accord._
import com.wix.accord.dsl._

import codes.reactive.scalatime._

import better.files._

import java.time._

import scala.collection.mutable
...
...

在 Scala 中 DRY 的最佳方法是什么?我可以为我的项目(使用某种 sbt 插件?)或在包级别指定所有这些吗?

【问题讨论】:

【参考方案1】:

我看到了一些可以解决您正在寻找的问题的方法。看看

定义的进口

https://github.com/mongodb/casbah/blob/master/casbah-core/src/main/scala/Implicits.scala

这种方法的小例子:

object Imports extends Imports with commons.Imports with query.Imports with query.dsl.FluidQueryBarewordOps

object BaseImports extends BaseImports with commons.BaseImports with query.BaseImports

object TypeImports extends TypeImports with commons.TypeImports with query.TypeImports

trait Imports extends BaseImports with TypeImports with Implicits

@SuppressWarnings(Array("deprecation"))
trait BaseImports 
  // ...
  val WriteConcern = com.mongodb.casbah.WriteConcern
  // More here ...


trait TypeImports 
  // ...
  type WriteConcern = com.mongodb.WriteConcern
  // ... 

使用的进口商品

https://github.com/mongodb/casbah/blob/master/casbah-core/src/main/scala/MongoClient.scala

当他们使用这个导入对象时,它会为您解锁所有类型别名。例如,WriteConcern

import com.mongodb.casbah.Imports._
// ...
def setWriteConcern(concern: WriteConcern): Unit = underlying.setWriteConcern(concern)

基本上他们将所有导入包装到一个公共 Import 对象中,然后只需使用 import com.mycompany.Imports._

Doobie 在大多数最终用户只是 import doobie.imports._

的情况下做了类似的事情

https://github.com/tpolecat/doobie/blob/series/0.3.x/yax/core/src/main/scala/doobie/imports.scala

再次,来自此模式的示例:

object imports extends ToDoobieCatchSqlOps with ToDoobieCatchableOps 
  /**
   * Alias for `doobie.free.connection`.
   * @group Free Module Aliases
   */
  val FC   = doobie.free.connection

  /**
   * Alias for `doobie.free.statement`.
   * @group Free Module Aliases
   */
  val FS   = doobie.free.statement

  // More here ...

这种方法与包对象样式的主要区别在于您可以更好地控制导入的内容/时间。我已经使用了这两种模式,通常是我需要跨内部包的常用实用程序方法的包对象。对于库,特别是我的代码的用户,我可以将某些隐式定义附加到导入对象,例如上面提到的doobie,这将为使用单个导入的用户解锁 DSL 语法。

【讨论】:

将别名放入包对象com.acme,则每个文件为package com.acme ; package projectx。无需导入。 @som-snytt:我不明白你的评论——也许发布一个新的答案?您可以使用我原来的问题中的导入 @pathikrit 我的意思是像另一个答案一样,从封闭包中获取别名。但很快您就可以使用-Yimports 来执行您的自定义预定义。我认为该选项的语法可能会在 2.13 之前更改,但 -Yimports:com.acme._ 或类似。【参考方案2】:

我可能会选择scala.Predef approach:基本上,为类型设置别名并公开我想要提供的对象。所以例如

package com.my

package object project 
  type LocalDate = java.time.LocalDate
  type LocalDateTime = java.time.LocalDateTime
  type LocalTime = java.time.LocalTime

  import scala.collection.mutable

  type MutMap[A, B] = mutable.Map[A, B]
  val MutMap = mutable.Map
  // And so on....

现在,无论您以package com.my.project 开头的文件,上述所有内容都将自动可用。顺便说一句,还要感谢 @som-snytt 的 pointing this out。

【讨论】:

您能根据 OP 原始问题中的导入来回答这个问题吗?我了解 Scala 和 Java 库中的简单内容可能会以这种方式工作,但是所有猫/尖顶导入呢? @pathikrit 将大量隐式导入到大量文件中我没有一个好的解决方案给你。事实上,现在我建议不要在文件顶部进行全面导入,而是尽可能在范围内(本地)导入:gist.github.com/yawaramin/f39b109a1acc9b8263ab38259cbf88f5

以上是关于在 Scala 中捆绑导入的主要内容,如果未能解决你的问题,请参考以下文章

在 Ammonite (scala) 中重新导入脚本

有条件的样式导入在reactjs中构建后就捆绑在一起

全局导入与单个组件导入 + webpack:最终(捆绑/打包)大小有啥区别吗?

捆绑为 UMD 的 React 组件在通过另一个 React 应用程序中的脚本标签导入时无法加载依赖项

使用 webpack 捆绑一个 React 组件以由另一个 React 组件导入

Scala 中如何解析导入的名称? (火花/齐柏林飞艇)