在Scala中约束更高层次的类型

时间:2012-02-08 05:42:03

标签: scala types

说我有更高的kinded类型

SuperMap[Key[_],Value[_]]`.  

现在假设我有更具体的内容要求Key的类型参数必须与Value的类型参数相匹配;就是这样的事情:

SuperDuperMap[T, Key[T], Value[T]]

进一步假设我不想要任何T,而是一个非常具体的T <: OtherT

SuperDuperPooperMap[T <: OtherT, Key[T], Value[T]]

这可以在Scala中完成吗?这通常是一个坏主意吗?有没有相同的方法来做这个更容易阅读/写/使用?

3 个答案:

答案 0 :(得分:11)

您的声明已按预期运行,即您限制T以及KeyValue的类型。但是,如果您发布类似

的内容,scala会抱怨您的写法
scala> class Foo[T <: OtherT, Key[T], Value[T]]
defined class Foo

scala> new Foo[SpecialOtherT, Key[SpecialOtherT], Value[SpecialOtherT]]
<console>:13: error: Key[SpecialOtherT] takes no type parameters, expected: one
              new Foo[SpecialOtherT, Key[SpecialOtherT], Value[SpecialOtherT]]

因为您之前的声明已经提供了KeyValue的类型。因此这将起作用

scala> new Foo[SpecialOtherT, Key, Value]
res20: Foo[SpecialOtherT,Key,Value] = Foo@3dc6a6fd

这可能不是你想要的。你可以这样做

scala> class Foo[T <: OtherT, K <: Key[T], V <: Value[T]]
defined class Foo

scala> new Foo[SpecialOtherT, Key[SpecialOtherT], Value[SpecialOtherT]]
res21: Foo[SpecialOtherT,Key[SpecialOtherT],Value[SpecialOtherT]] = Foo@7110506e

在底线,由于KeyValue的类型完全取决于T,因此在使用Foo时获取所有冗余信息有点多余。那么为什么不使用这样的内部类型声明:

class Foo[T <: OtherT] {
  type K = Key[T]
  type V = Value[T]
}

然后您可以从班级中访问类型KV,但每次创建新答案时都不需要输入类型:

scala> new Foo[SpecialOtherT]
res23: Foo[SpecialOtherT] = Foo@17055e90

scala> new Foo[Int]
<console>:11: error: ...

答案 1 :(得分:3)

可以在Scala中完成吗?

你是什​​么意思?你刚才做到了!

这通常是一个坏主意吗?

为什么会这样?事实上,这是一个好主意!这就是高等级的类型。

是否有相同的方法可以更容易地进行读/写/使用?

阅读 - 对我来说非常好。

写作 - 编写/测试/编译一次,随处使用。

使用 - 编译器将重建(推断)“无处不在”的类型。

答案 2 :(得分:2)

你可能不需要比几个类型别名更复杂的东西,

type SuperDuperMap[T, Key[_], Value[_]] = SuperMap[Key, Value]

type SuperDuperPooperMap[T <: OtherT, Key[_], Value[_]] = SuperMap[Key, Value]

示例REPL会话,

scala> new SuperDuperMap[Int, Option, List] {}
res0: java.lang.Object with SuperDuperMap[Int,Option,List] = ...

scala> new SuperDuperPooperMap[OtherT, Option, List] {}
res1: java.lang.Object with SuperDuperPooperMap[OtherT,Option,List] = ...