2016-11-30 3 views
1

Я разрабатываю библиотеку, которая зависит от другой. У зависимостей есть package object, что я хотел бы добавить псевдоним в свой собственный домен пакета, чтобы «скрыть» базовую библиотеку от пользователей той, которую я разрабатываю, для потенциальной последующей повторной реализации этой библиотеки. Я попробовал несколько вещей, в том числеСложение объектов пакета Scala

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

Это компилирует, но import renamedfunctions._ ничего не приносит в рамки. Я также попытался расширить объект поддержки, но объекты scala не расширяются. Кто-нибудь знает, как сделать то, что я пытаюсь сделать, не накрывая основную библиотеку?

ответ

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 = [email protected] 

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) 
      ^

Ok, так что вы должны делать?

Причина, по которой вы даже рассматриваете это, заключается в том, что вы хотите скрыть реализацию той библиотеки, которую вы используете, чтобы ее можно было легко заменить позже. Если это так, то вам следует скрыть библиотеку в другом интерфейсе или объекте (фасад). Это не означает, что вам нужно пересылать каждый метод и значение, содержащиеся в библиотеке, только тот, который вы фактически используете. Таким образом, когда дело доходит до перехода на другую библиотеку, вам нужно только изменить один класс, потому что остальная часть кода будет ссылаться только на фасад.

Например, если мы хотим использовать 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), чтобы классы могли вводить различные реализации.

+0

Это середина разметки библиотеки и наложение объекта пакета, который мой мозг не смог синтезировать. Немного утомительно, но это дает мне больше контроля, спасибо! –

1

Просто:

val renamedfunctions = functions 

import renamedfunctions._ 

Вы можете видеть, что это делается в самой библиотеке лестницу: https://github.com/scala/scala/blob/2.12.x/src/library/scala/Predef.scala#L150

val Map = immutable.Map 
+0

Кажется, что это работает в контексте класса/объекта/признака, не совсем того, что я искал, но у @ micheal-zajac был идеальный ответ выше. Благодаря! –

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) 
    } 
} 

Это сделало бы клиенты не ломаются, когда вы мигрировали к реализации в объекте пакета.

Смежные вопросы