一直玩scalas類型系統,我再次發現自己與它戰鬥。我爲一些簡單的圖形應用程序創建了一個Vector庫,並且對它非常滿意。scala更高類型和scalatic平等
現在我想能夠用scalacheck和scalatest測試Vector屬性,到目前爲止這麼好。我現在面臨的問題是,使用double或float時檢查向量的平等並不像我想的那麼簡單。現在我認爲測試框架中最習慣的方式是爲我的矢量類創建一個new Equality
。但是讓我們退後一步,看看我的矢量defenitions
abstract class Vec[T, V[T] <: Vec[T, V]](val elems: T*)(implicit num: VecIntegral[T], factory: VecFactory[V])
class Vec2[T](x: T, y: T)(implicit num: VecIntegral[T]) extends Vec[T, Vec2](x,y)
Vec3[T](x: T, y: T, z: T)(implicit num: VecIntegral[T]) extends Vec[T, Vec3](x,y, z)
此處也未表示不應用和應用都爲VEC對象允許模式匹配等中規定。
所以,現在我寫的測試第一次嘗試看起來像這樣
abstract class VecSuite[T: Arbitrary, V[T] <: Vec[T, V]](implicit genVec: Arbitrary[V[T]], num: VecIntegral[T])
extends PropSpec with PropertyChecks {
import num._
property("associative add") {
forAll { (a: V[T], b: V[T]) =>
assert((a + b).===(b + a))
}
}
property("scalar distributed") {
forAll { (a: V[T], b: V[T], s: T) =>
assert((a + b) * s === a * s + b * s)
}
}
...
}
class Vec2IntSuite extends VecSuite[Int, Vec2]
class Vec2FloatSuite extends VecSuite[Float, Vec2]
class Vec2DoubleSuite extends VecSuite[Double, Vec2]
class Vec2LongSuite extends VecSuite[Long, Vec2]
在這裏再次我不表演,但我有Vec2[T]
和Vec3[T]
類實現隱工廠。
所以這工作得很好。我編寫了一般測試,可以將它們應用到我所有不同的支持的Vector實現中,除了對於Float
和Double
,我得到四捨五入錯誤並且我的平等檢查爆炸。
所以現在我開始與Equality
類試圖使它一般Vec2
和Vec2
,這樣我只需要兩個隱含值Double
和Float
試圖之間打轉轉:
implicit val doubleEq = new Equality[ V[Double] forSome{ type V[Double] <: Vec[Double, V] }] {
override def areEqual(a: V[Double] forSome {type V[Double] <: Vec[Double, V]}, b: Any): Boolean = (a,b) match {
case (lhs: Vec[Double, _], rhs: Vec[Double, _]) => lhs.elems.zip(rhs.elems).forall {case (e1, e2) => e1 === e2 +- 0.01d }
case _ => false
}
}
但這不坐編譯器很好,它爆炸了java.lang.StackOverflowException
。
是否有寫Equality
的類型,以便將隱含在我的測試用例可以使用任何方式irregardless如果是Vec2
或Vec3
,只要它是Double
類型的?