Scala:在某个包的所有子包中导入隐式转换

Nae*_*mul 6 scala package implicit-conversion

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

package com.gmail.naetmul.stackoverflow.app

object Implicits {
  implicit def int_to_intEx(x: Int): IntEx = IntEx(x)
}
Run Code Online (Sandbox Code Playgroud)

这个对象在某个包中.我想在包中的每个代码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._
}
Run Code Online (Sandbox Code Playgroud)

但它不能在确切的包对象之外工作.所以我将对象更改Implicitstrait并让包对象扩展它.

package com.gmail.naetmul.stackoverflow.app

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

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

package object app extends Implicits {
  // some code
}
Run Code Online (Sandbox Code Playgroud)

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

例如)

文件 A.scala

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

class A {
  // Here, the implicit conversion did NOT work.
}
Run Code Online (Sandbox Code Playgroud)

文件 B.scala

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

class B {
  // Here, the implicit conversion DID work.
}
Run Code Online (Sandbox Code Playgroud)

所以问题是:

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

  2. 是否有另一种方法可以在子包中使用隐式转换?我的意思是,只导入一次,并在任何地方使用它们.工作方式B.scala似乎很好,但Eclipse的默认包语句就像A.scala,所以我必须手动更改它们.

som*_*ytt 3

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

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

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

我从你的部分例子中猜测你想用像odd. 对于此用例,提供缺少的成员,您必须像所做的那样提供转换。

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

给定一个 API:

package goofy

object API { 
  def api(i: IntEx) = i.odd
}
Run Code Online (Sandbox Code Playgroud)

以及子包中的 API 客户端:

package goofy.foo.bar.baz

import org.junit.Test

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

您导入了 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)
}
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为它IntEx是预期的类型。您还可以以相同的方式利用类型参数。

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

package roofy

import org.junit.Test 

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