【问题标题】:Scala: Importing implicit conversions in all subpackages of some packageScala:在某个包的所有子包中导入隐式转换
【发布时间】:2014-01-07 02:47:00
【问题描述】:

我在object 中定义了隐式转换。让我们调用对象Implicits,其中有一个隐式转换。

package com.gmail.naetmul.stackoverflow.app

object Implicits {
  implicit def int_to_intEx(x: Int): IntEx = IntEx(x)
}

这个对象在某个包中。我想在包com.gmail.naetmul.stackoverflow.app 及其所有子包(如com.gmail.naetmul.stackoverflow.app.something.anything.everything)中的每个代码中使用这种隐式转换。

所以我做了com.gmail.naetmul.stackoverflow.app的包对象。

package com.gmail.naetmul.stackoverflow

package object app {
  import com.gmail.naetmul.stackoverflow.app.Implicits._
}

但它在确切的包对象之外不起作用。 于是我把对象Implicits改成了trait,让包对象扩展它。

package com.gmail.naetmul.stackoverflow.app

trait Implicits {
  implicit def int_to_intEx(x: Int): IntEx = IntEx(x)
}
package com.gmail.naetmul.stackoverflow

import com.gmail.naetmul.stackoverflow.app.Implicits

package object app extends Implicits {
  // some code
}

隐式转换在包com.gmail.naetmul.stackoverflow.app 中起作用。但是,它在子包中工作或不工作。

例如)

文件A.scala

package com.gmail.naetmul.stackoverflow.app.database

class A {
  // Here, the implicit conversion did NOT work.
}

文件B.scala

package com.gmail.naetmul.stackoverflow.app
package database

class B {
  // Here, the implicit conversion DID work.
}

所以问题是:

  1. 在这种情况下我应该使用trait 而不是object(与包对象一起使用,但在外部定义)?

  2. 还有其他方法可以在子包中使用隐式转换吗? 我的意思是,只导入一次,并在任何地方使用它们。 B.scala 中的工作方式看起来不错,但是 Eclipse 的默认包语句类似于 A.scala,所以我必须手动更改它们。

【问题讨论】:

  • B.scala 中的多行包声明是获得你想要的行为的方式。如果你把它放在像 A.scala 这样的一行上,你只会得到那个包的包对象。我不相信有任何其他方法可以实现这一目标。因此,我认为您要么手动更改这些声明,要么说服 Eclipse 这样做。我使用 IntelliJ IDEA,为此您可以为每个模块指定基本包,它会使子包中任何代码的包声明自动使用两行(基本一行,其余行)。

标签: scala package implicit-conversion


【解决方案1】:

对于问题 1,将超类中的隐式存储为“LowPriorityImplicits”可能很有用,但这似乎不是这里的用例。

对于问题 2,嵌套包是将隐式带入范围的常用方法。关于“包装”的规范 9.2 使用了神奇的短语“在它们的简单名称下可见”。

但是有一些策略可以利用隐式作用域。

我从您的部分示例中猜想您想使用odd 之类的方法来增强 Int。对于这个用例,提供缺少的成员,您必须提供转换。

但 API 设计还有其他选择。例如:

给定一个 API:

package goofy

object API { 
  def api(i: IntEx) = i.odd
}

和一个子包中的 API 客户端:

package goofy.foo.bar.baz

import org.junit.Test

class UseIntExTest {
  import goofy.API._
  @Test def usage(): Unit = {
    assert(api(3))
  }
}

您在哪里导入了 API,并且“免费”获得了隐式范围。

转换在伴随对象中:

package goofy

class IntEx(val i: Int) {
  def even = i % 2 == 0
  def odd  = !even
}

object IntEx {
  implicit private[goofy] def `enhanced IntEx`(i: Int): IntEx = new IntEx(i)
}

这是可行的,因为 IntEx 是预期的类型。你也可以以同样的方式利用类型参数。

为了完整起见,表明转换仅限于子包:

package roofy

import org.junit.Test 

class BadUsageTest {
  import goofy.API._
  @Test def usage(): Unit = {
    //assert(api(3))  // DNC
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-02
    • 1970-01-01
    • 1970-01-01
    • 2014-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多