【发布时间】:2021-01-06 12:46:59
【问题描述】:
我在使用 ScalaTest 时遇到了一个非常难以调试的错误。奇怪的是,当我的程序没有 Main 对象时似乎会发生这种情况,但当它确实有 Main 对象时则不会。我的代码实际上只是使用带有多态方法的类型类从列表中获取切片,并且看起来像这样(对于稍微冗长的示例表示歉意,我已尽可能减少它):
package sportarray
object ArrayDefs {
abstract class IsArr[A, I0, DT] {
def getElem(self: A, i: Int): DT
def getSlice[R](self: A, r: R)(implicit sliceTc: IsSlice[R]): sliceTc.Out = sliceTc.getSlice(self, r)
trait IsSlice[R] {
type Out
def getSlice(self: A, ref: R): Out
}
object IsSlice {
implicit val iLocTCForInt = new IsSlice[Int] {
type Out = DT
def getSlice(self: A, ref: Int): Out = getElem(self, ref)
}
implicit val iLocTCForList = new IsSlice[List[Int]] {
type Out = List[DT]
def getSlice(self: A, ref: List[Int]): Out = ref.map(getElem(self, _))
}
}
}
object IsArrSyntax {
implicit class IsArrOps[A, I0, T](self: A)(implicit
tc1d: IsArr[A, I0, T]
) {
def getElem(i: Int) = tc1d.getElem(self, i)
def getSlice[R](r: R)(implicit sliceTc: tc1d.IsSlice[R]) = tc1d.getSlice(self, r)
}
}
}
object ListOfListsObj {
import ArrayDefs._
case class List1d[I0, T] (
indices: List[I0],
data: List[T],
)
implicit def list1dIs1dSpArr[A, I0, T] =
new IsArr[List1d[I0, T], I0, T] {
def getElem(self: List1d[I0, T], i: Int) = self.data(i)
}
}
我的测试很简单,看起来像这样,在测试目录下自己的文件中:
package sportarray
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class ArraySpec extends AnyFlatSpec with Matchers {
"List" should "act as an array" in {
import ArrayDefs._
import ArrayDefs.IsArrSyntax._
import ListOfListsObj._
val list1d = List1d[Int, Double](List(1,2,3), List(1.0, 2.0, 3.0))
assert(list1d.getSlice(1) == 2.0)
}
}
如果我按原样sbt test 这段代码,我会收到以下错误:
java.lang.NoSuchFieldError: sportarray$ArrayDefs$IsArrSyntax$IsArrOps$$tc1d
at sportarray.ArraySpec.$anonfun$new$1(HelloSpec.scala:12)
at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
at org.scalatest.Transformer.apply(Transformer.scala:22)
at org.scalatest.Transformer.apply(Transformer.scala:20)
at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1683)
然后我尝试在程序中添加一个 Main 类,看看这是测试的问题,还是代码本身的问题:
object Main extends App {
import ArrayDefs._
import ArrayDefs.IsArrSyntax._
import ListOfListsObj._
val list1d = List1d[Int, Double](List(1,2,3), List(1.0, 2.0, 3.0))
assert(list1d.getSlice(1) == 2.0)
}
如果我 sbt run 可以正常工作,而且奇怪的是,它还允许我运行 sbt test 没有任何问题。如果我随后删除这个主类,sbt test 将再次失败。有没有人能解释一下这里发生了什么?
感谢您的帮助!
【问题讨论】:
-
可能是带有反射(在 Scalatest 中使用)和嵌套的东西。如果您删除对象
ArrayDefs使其内容成为顶级,则测试成功运行。 -
在我将
val添加到implicit class IsArrOps[A, I0, T](self: A)(implicit val tc1d...之后,sbt clean test成功运行(在 IntelliJ 中也是如此)。 -
@DmytroMitin - 谢谢 - 这似乎是最简单的解决方法。
标签: scala reflection typeclass scalatest