别名Scala包对象

时间:2016-11-30 21:12:32

标签: scala

我正在开发一个依赖于另一个库的库。依赖项有一个package object,我希望将其替换到我自己的包域中,以便从我正在开发的那个用户中“隐藏”底层库,以便以后重新实现该库。我尝试了几件事,包括

object functions {
  def identity(a: Any): Any = a
  def toUpper(s: String): String = s.toUpperCase
}
object renamedfunctions {
  import functions._
}

这个编译,但import renamedfunctions._没有任何内容。我也尝试扩展后备对象,但scala对象是不可扩展的。有没有人知道如何在不牺牲底层库的情况下完成我想要做的事情?

3 个答案:

答案 0 :(得分:4)

一般来说,使用Scala软件包是不可能的。通常,您只能在文件中本地对包进行别名:

import scala.{ math => physics }

scala> physics.min(1, 2)
res6: Int = 1

但这不符合你的要求。包本身不是值或类型,因此您不能这样分配它们。这些将失败:

type physics = scala.math
val physics = scala.math

使用包对象,你可以抓住它的具体成员,但不能抓住其中的类。例如:

scala> val physics = scala.math.`package`
physics: math.type = scala.math.package$@42fcc7e6

scala> physics.min(1, 2)
res0: Int = 1

但是使用属于传统包的对象或类型将不起作用:

scala> scala.math.BigDecimal(1)
res1: scala.math.BigDecimal = 1

scala> physics.BigDecimal(1)
<console>:13: error: value BigDecimal is not a member of object scala.math.package
       physics.BigDecimal(1)
               ^

好的,那你该怎么办?

您甚至考虑这个问题的原因是您希望隐藏您正在使用的库的实现,以便以后可以轻松替换它。如果是这种情况,您应该做的是将库隐藏在另一个接口或对象( facade )中。这并不意味着您需要转发库中包含的每个方法和值,而只需要转发您实际使用的方法和值。这样,当涉及到迁移到另一个库时,您只需要更改一个类,因为其余代码只会引用外观。

例如,如果我们想要使用min中的maxscala.math,但后来想要将其替换为另一个提供更有效解决方案的库(如果存在这样的事情) ),我们可以创建这样的外观:

object Math {
    def min(x: Int, y: Int): Int = scala.math.min(x, y)
    def max(x: Int, y: Int): Int = scala.math.max(x, y)
}

所有其他类都会使用Math.minMath.max,因此当scala.math被替换时,它们可以保持不变。您还可以使Math成为一个特征(没有实现)并在子类或对象(例如ScalaMath)中提供实现,这样类可以注入不同的实现。

答案 1 :(得分:2)

不幸的是,注释掉的代码会使编译器崩溃:

package object p { def f = 42 }

package q {
  object `package` { def f = p.f }
}
/*
package object q {
  val `package` = p.`package`
}
*/

package client {
  import q.`package`._
  object Test extends App {
    println(f)
  }
}

这会使客户端在迁移到包对象中的实现时不会中断。

答案 2 :(得分:1)

简单地:

val renamedfunctions = functions

import renamedfunctions._

您可以在scala库本身中看到它:https://github.com/scala/scala/blob/2.12.x/src/library/scala/Predef.scala#L150

val Map = immutable.Map