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

Scala generic type alias in trait - Wrong number of type arguments

我认为下面的代码肯定可以工作,但它报告错误"Wrong number of type arguments. Expected: 2, actual: 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 中实现这种结构的最佳方法是什么?

将类型参数视为函数参数。这里有 2 个不同的东西,T 包含在 Seq 中,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 已经在 class 的类型参数中定义为参数。 MyImpl 保持未知的 K 和 T 两种类型,而 MyCache 将这些类型固定为具体的 classes 并且不再是抽象的。

您可以像在 trait/class 正文中使用 Key 那样声明它们,而不是显式地声明类型参数,并让它们抽象,直到您在 sub[=28 中修复它们的值=] 或子特征。

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 将 return Option[Option[Seq[T]]]看起来不容易使用,所以最后我会写一个缓存:

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

这是 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]
}

正如我在评论中所说,代码确实可以编译(使用 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]
}