我经常通过使用Guice,TypeLiteral
,泛型和通配符来推动Java类型系统的限制。我经常遇到需要执行未经检查的强制转换的情况,这几乎破坏了类型安全 - 换句话说,“泛型地狱。”
这是我的一些有问题的Java代码的简化示例。
class SquareDrawer implements ShapeDrawer<Row<Square>> {}
class Client {
Key<SquareDrawer> SQUARE_DRAWER_KEY =
Key.get(SquareDrawer.class, randomAnnotation());
void bindShapeDrawer(
Key<? extends ShapeDrawer<Row<? extends Shape>>> shapeDrawer) {}
Client() {
// Note Unchecked cast required below
bindShapeDrawer(
(Key<? extends ShapeDrawer<Row<? extends Shape>>>) SQUARE_DRAWER_KEY);
}
}
我一直在学习Scala,并且一直认为它比Java更能支持泛型。以上代码是否可以用Scala编写以避免未经检查的强制转换?
Scala中仍然需要Guice的TypeLiteral
吗?
答案 0 :(得分:3)
Scala提供了一些东西。
更高级的类型(我希望我正确地使用这个术语)允许你定义诸如“任何类型具有另一种类型作为类型参数”之类的东西afaik没有办法在java中表达
< / LI>Co和Contravariant类型参数。在java中,您可以通过在使用它们的每个位置使用通配符来创建参数。在Scala中你只需要声明它们。
类型见证(再次:这是正确的术语吗?)是隐式函数,它们演示了类型参数的某些属性,从而定义了对类型的约束。如果存在与见证声明匹配的隐式转换,则调用将编译条件成立。
路径依赖类型。您可以拥有作为实例元素的类型,因此每个实例都有自己的类型。再一次,你不能在java afaik中做到这一点。
答案 1 :(得分:2)
Scala的形式为reified types,称为Manifest。由于类型擦除,它们允许你做一些在Java中非常笨重的事情。在这里阅读所有相关信息:http://www.scala-blogs.org/2008/10/manifests-reified-types.html
答案 2 :(得分:2)
以下(希望)等效的Scala代码编译时没有错误。也许我需要声明它不包含动态转换。请注意,我必须在其类型参数中设置Key
协变,因为SquareDrawer
只是ShapeDrawer[Row[Square]]
的子类型。
trait ShapeDrawer[A]
trait Row[A]
trait Shape
trait Square extends Shape
trait Key[+A]
//your code starts here
trait SquareDrawer extends ShapeDrawer[Row[Square]]
class Client{
val SDK = new Key[SquareDrawer]{}
bindShapeDrawer(SDK)
def bindShapeDrawer[SD[A] <: ShapeDrawer[A],S <: Shape](shapeDrawer: Key[SD[Row[S]]]) {}
}