scala - 使用类型类使 OpenGL 的 int 常量类型安全
问题描述
我打算在 lwjgl 周围创建一个类型安全的包装器。最重要的是,我希望将错误的常量传递给函数是编译时错误,例如调用glEnable(GL_ARRAY_BUFFER)
. 如果不是不同的上下文支持同一函数的不同常量,这将相当容易。
我想我会使用类型类来模拟哪些常量可以传递给哪个函数。我有一个解决方案,但不可否认它有点难看,并且没有应用某种隐含的:
trait GlConst { val glConst: Int }
trait GlConstCompanion[C <: GlConst] { val instance: C }
class GlDepthTest private () extends GlConst { val glConst = GL_DEPTH_TEST }
object GlDepthTest extends GlConstCompanion[GlDepthTest] {
val instance = new GlDepthTest
}
class GlLineSmooth private () extends GlConst { val glConst = GL_LINE_SMOOTH }
object GlLineSmooth extends GlConstCompanion[GlLineSmooth] {
val instance = new GlLineSmooth
}
class GlArrayBuffer private () extends GlConst { val glConst = GL_ARRAY_BUFFER }
object GlArrayBuffer extends GlConstCompanion[GlArrayBuffer] {
val instance = new GlArrayBuffer
}
// type class for arguments to glEnable
trait GlEnableCap[T <: GlConst] extends GlConst
object GlContext33 {
implicit object GlDepthTestIsEnableCap extends GlEnableCap[GlDepthTest] {
val glConst = GlDepthTest.instance.glConst
}
implicit object GlLineSmoothIsEnableCap extends GlEnableCap[GlLineSmooth] {
val glConst = GlLineSmooth.instance.glConst
}
def glEnable[T <: GlConst : GlEnableCap](t: T): Unit = println(implicitly[GlEnableCap[T]].glConst)
}
object Test extends App {
import GlContext33._
implicit def constComp2Const[C <: GlConst](cc: GlConstCompanion[C]): C = cc.instance
// works
glEnable(GlDepthTest.instance)
// fails to apply implicit glConstComp2Comp
glEnable(GlDepthTest)
// fails intentionally
glEnable(GlArrayBuffer)
}
有没有办法让隐式工作?还是有更好的方法来包装 OpenGL 的常量?
解决方案
根据经验,implicit
如果不需要,请不要使用 s。在这种情况下,您也可以仅使用类型边界来解决它:
// Start writing your ScalaFiddle code here
val GL_DEPTH_TEST = 1
val GL_LINE_SMOOTH = 1
val GL_ARRAY_BUFFER = 1
trait GlConstCap
trait GlEnableConstCap extends GlConstCap
trait GlBufferConstCap extends GlConstCap
trait GlConst[C <: GlConstCap] { val value: Int }
object GlDepthTest extends GlConst[GlEnableConstCap] {
val value = GL_DEPTH_TEST
}
object GlLineSmooth extends GlConst[GlEnableConstCap] {
val value = GL_LINE_SMOOTH
}
object GlArrayBuffer extends GlConst[GlBufferConstCap] {
val value = GL_ARRAY_BUFFER
}
object GlContext33 {
def glEnable[T <: GlConst[GlEnableConstCap]](t: T): Unit = println(t.value)
}
object Test extends App {
import GlContext33._
// works
glEnable(GlDepthTest)
// fails to apply implicit glConstComp2Comp
glEnable(GlDepthTest)
// fails intentionally
glEnable(GlArrayBuffer)
}
注意:如果要创建C
.GlConst
GlConstCap
我希望这有帮助。
推荐阅读
- flutter - 无法将用户从 Auth0 同步到 Hasura
- java - 检测动画何时结束(Android Studio)
- angular - 使用 strictNullChecks 从可能为 null 的属性中键入别名
- html - Bootstrap 4 修复导航栏的问题
- php - 如何为 PATHINFO() 添加 readline 函数(扩展)
- node.js - 如何调用另一个类的函数或导出的对象?
- android - Firebase 实时数据库 - ChildEventListener - 基础
- python - 是否有一个 API 可以仅从其名称 (AppName) 中获取 Steam AppID?
- go - 使用以编程方式编写并连接到 os.stdin 的标准输入执行命令
- azure - 使用 webjobs 从 Azure 上的 SQL Server 数据库中删除记录的脚本