我可以在Scala中使用哪些技术来处理长类型参数列表?
我正在开发一个用于运行具有不同模拟环境的各种类型游戏的小框架。我试图保持框架的某些部分相对通用,所以我将各种类型作为类型参数引入,例如环境状态,游戏结果等。
这一切在功能上都运行良好,我确实获得了类型安全但通用框架的预期好处。但是类型签名已经发展到了使代码难以阅读和重构的程度,它变得非常麻烦。顶级模拟器的签名有八个类型参数,许多主要类型有三到五个。单个编译器类型错误,因为它们列出了类或函数参数的类型(当然也是类型参数化的)似乎经常运行到一百行。
偶尔,但很少,我可以省略类型参数,例如在构造函数上。但在大多数情况下,至少有一种类型不会被推断,所以我最终不得不插入整个类型的签名。
显然这不太理想,我正在寻找解决这个问题的方法。任何建议将不胜感激!
答案 0 :(得分:10)
我想到了两种解决方案。
使用类型别名。
scala> class Foo[A, B, C, D, E]
defined class Foo
scala> type Bar[A] = Foo[A, Int, Int, Int, Float]
defined type alias Bar
scala> new Bar[String]
res23: Foo[String,Int,Int,Int,Float] = Foo@f590c6
使用abstract type members代替类型参数。
scala> class Bar {
| type A
| type B <: AnyVal
| type C
| }
defined class Bar
scala> new Bar {
| type A = String
| type B = Int
| type C = Int
| }
res24: Bar{type A = String; type B = Int; type C = Int} = $anon$1@ee1793
scala> trait Baz {
| type A = String
| }
defined trait Baz
scala> new Bar with Baz {
| type B = Int
| type C = String
| }
res25: Bar with Baz{type B = Int; type C = String} = $anon$1@177c306
scala> null.asInstanceOf[res25.A]
res26: res25.A = null
scala> implicitly[res25.A =:= String]
res27: =:=[res25.A,String] = <function1>
您可能希望与我们分享一些代码,以便我们提供更具体的建议。
答案 1 :(得分:7)
考虑具有一组密切相关的类型参数的情况;你把它们作为类型参数传递给它们。在此示例中,该组为A
和B
。
trait X[A, B, C] {
new Y[A, B, Int] {}
}
trait Y[A, B, D] {
def a: A = sys.error("")
}
您可以将这两种类型打包成一个类型参数,其类型别名包含类型成员:
type AB = { type A; type B }
trait Y[ab <: AB, D] {
def a: ab#A = sys.error("")
}
trait X[ab <: AB, C] {
new Y[ab, C] {}
}
new X[{ type A=Int; type B=Int}, String] {}