我认为以下代码肯定会起作用,但它报告错误"类型参数数量错误。预期: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
}
但是我对斯卡拉斯类型系统有什么误解?为什么我不能在"MyImpl"中创建不同的 Cache[T] 实现。例如,为什么我不能在MyImpl中创建Cache[String]和Cache[Int]?
最后,在 Scala 中实现这种结构的最佳方式是什么?
正如我在评论中所说,代码确实可以编译(使用 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]
}
将类型参数视为函数参数。在这里,您有 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 body 中对 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]
}
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]
}