在Scala 2中,你当然可以使用通配符或存在类型作为类型参数。然而,这意味着你并不总是有一个你想使用的类型的名称。这有时会导致奇怪的情况,你需要依靠类型推理来避免显式地编写类型。
下面是一个有点做作的例子来说明我的意思:
case class Container[T](value: T) {
def replace(value: T): Container[T] = Container(value)
}
def identity[T](container: Container[T]): Container[T] = {
// A weird way of writing the identity function,
// but notice that I have essentially given the name
// `T` to the `_`
container.replace(container.value)
}
var x: Container[_] = Container[Int](1)
// This works, but as far as I know, there's no way to explicitly
// pass the type for `T`. For example, something like identity[_](x) won't work.
identity(x)
// This also fails to work, but if we could assign a name to the `_`, like `T`,
// then it would become obvious that this should work.
// x.replace(x.value)
有没有更简洁的方法来解决这个问题?如果你能写这样的话,那就太好了:
let Container[T] = x.type in {
// Now there is a type T in this scope,
// and x has type `Container[T]`
}
据我所知,Scala中不存在这样的功能。我是不是遗漏了什么功能?还有,有人知道其他语言中有类似的功能吗?
2条答案
按热度按时间3htmauhk1#
使用类型模式匹配(使用2.13测试):
实际的类型本身在代码中没有名称,并且实际上不可见,但基本上发生的是这样的:
类型模式
t
绑定存在量化类型,并且可以在后续表达式中使用,从而可以对v: t
进行类型化,并且也可以对c.replace(v)
进行正确类型化。另见以下相关问题:
fbcarpbf2#
还有一种选择是将
T
作为类型成员而不是类型参数。在这种情况下,存在类型只对应于Container
,而特定类型是Container { type T = ... }
(又名Container.Aux[...]
)。不幸的是,类型成员类型不能用于类主构造函数所以我用trait + factory方法替换了case类
请注意,我将
x
设置为val
而不是var
,这样依赖于路径的类型x.T
才有意义。也许你更喜欢保留case类,因为编译器为case类生成了很多语法糖,在这种情况下,我们可以引入一个额外的trait