【问题标题】:Aliasing Scala package objects别名 Scala 包对象
【发布时间】:2017-04-15 08:40:56
【问题描述】:

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

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

这会编译,但 import renamedfunctions._ 不会将任何内容带入范围。我也尝试过扩展支持对象,但 scala 对象是不可扩展的。有谁知道在不分叉底层库的情况下完成我想要做的事情的方法?

【问题讨论】:

    标签: scala


    【解决方案1】:

    一般来说,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)中。这并不意味着您需要转发库中包含的每个方法和值,只需要转发您实际使用的方法和值。这样,在迁移到另一个库时,您只需要更改一个类,因为其余代码将仅引用外观。

    例如,如果我们想使用 scala.math 中的 minmax,但后来想用另一个提供更有效解决方案的库替换它(如果存在这样的东西),我们可以创建一个像这样的外观:

    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),以便类可以注入不同的实现。

    【讨论】:

    • 这是我的大脑无法合成的库和别名包对象的中点。有点乏味,但它给了我更多的控制权,谢谢!
    【解决方案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)
      }
    }
    

    当您迁移到包对象中的实现时,客户端不会中断。

    【讨论】:

      【解决方案3】:

      简单地说:

      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
      

      【讨论】:

      • 似乎这在类/对象/特征的上下文中有效,这不是我想要的,但@micheal-zajac 在上面有一个理想的答案。谢谢!
      猜你喜欢
      • 2011-04-24
      • 1970-01-01
      • 1970-01-01
      • 2017-01-10
      • 1970-01-01
      • 2017-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多