特征中的Scala泛型类型别名 - 类型参数的数量错误

时间:2015-03-10 22:11:55

标签: scala generics types

我认为以下代码可以肯定,但它会报告错误"错误的类型参数数量。预期:2,实际:1"

trait MyTrait[T] {
  type Things = Seq[T]
  type Cache[K] = scala.collection.mutable.HashMap[K, Option[Things]]
}
abstract class MyImpl[T] extends MyTrait[T] {
  val cache = new Cache[String]
}

我已将其更改为:

trait MyTrait[T] {
  type Things = Seq[T]
  type Key
  type Cache = scala.collection.mutable.HashMap[Key, Option[Things]]
}
abstract class MyImpl[T] extends MyTrait[T] {
  type Key = String
  val cache = new Cache
}

但是我对scalas类型系统的误解是什么?为什么我不能在' MyImpl'中创建不同的Cache [T]实现。例如。为什么我不能在MyImpl中创建Cache [String]和Cache [Int]?

最后,在Scala中实现这种结构的最佳方法是什么?

3 个答案:

答案 0 :(得分:3)

正如我在评论中所说,代码确实编译(使用scalac):

trait MyTrait[T] {
  type Things = Seq[T]
  type Cache[K] = scala.collection.mutable.HashMap[K, Option[Things]]
}
abstract class MyImpl[T] extends MyTrait[T] {
  val cache = new Cache[String]
}

答案 1 :(得分:0)

将类型参数视为函数参数。这里有2件不同的东西,Seq中包含的T和用作缓存的键的K. 对于函数,您可以写:myTraitFactory(t, k) 对于类型参数,您可以编写MyTrait[T, K]

这给了我们:

trait MyTrait[K, T] {
  type Things = Seq[T]
  type Cache = scala.collection.mutable.HashMap[K, Option[Things]]
}
abstract class MyImpl[K, T] extends MyTrait[K, T] {
  val cache = new Cache
}
class MyCache extends MyImpl[String, Cacheable]

您不需要编写Cache [K],因为K已经被定义为类的类型参数中的参数。 MyImpl保留了2种K和T未知的类型,而MyCache将这些类型修复为具体类,并且不再是抽象的。

您可以像在trait / class体中使用Key一样声明它们,而不是明确类型参数,并将它们保留为抽象,直到您将它们的值固定在子类或子特征中。

trait MyTrait {
  type T
  type Key
  type Things = Seq[T]
  type Cache = scala.collection.mutable.HashMap[Key, Option[Things]]
}
abstract class MyImpl extends MyTrait {
  type Key = String
  val cache = new Cache // using Strings as keys
}
class MyCache extends MyImpl {
  type T = Cacheable
}

你的缓存可能不需要存储与没有值相关联的密钥(None),否则cache.get将返回Option [Option [Seq [T]]],这看起来不容易,所以最后我会写一个缓存:

trait MyTrait[K, T] {
  type Things = Seq[T]
  type Cache = scala.collection.mutable.HashMap[Key, Things]
}

答案 2 :(得分:0)

这是Intellij IDEA的错误。下面的代码确实编译:

trait MyTrait[T] {
  type Things = Seq[T]
  type Cache[K] = scala.collection.mutable.HashMap[K, Option[Things]]
}
abstract class MyImpl[T] extends MyTrait[T] {
  val cache = new Cache[String]
}