我正在开发一个依赖于另一个库的库。依赖项有一个package object
,我希望将其替换到我自己的包域中,以便从我正在开发的那个用户中“隐藏”底层库,以便以后重新实现该库。我尝试了几件事,包括
object functions {
def identity(a: Any): Any = a
def toUpper(s: String): String = s.toUpperCase
}
object renamedfunctions {
import functions._
}
这个编译,但import renamedfunctions._
没有任何内容。我也尝试扩展后备对象,但scala对象是不可扩展的。有没有人知道如何在不牺牲底层库的情况下完成我想要做的事情?
答案 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
中的max
和scala.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.min
和Math.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