Scala 如何在获取泛型的同时传入子 class 然后 return 相同的子 class 类型?

Scala how to pass in child class and then return the same child class type while getting it generic?

我有一个这样的方法定义

def batchCacheable[T: ClassTag](cacheKeys: Seq[CacheKey])(callServiceToFetchValues: Seq[CacheKey] => Try[Map[CacheKey, T]]): Try[Map[CacheKey, T]] 

其中 CacheKey 是一个定义为具有称为 buildCacheKey 的单一方法的特征,我有一个案例 class 扩展了该特征并在其中也有一个 id。

trait CacheKey {
  def buildCacheKey: String
}

case class IDCacheKey(id: String) extends CacheKey {
  override def buildCacheKey: String = {
    s"CacheKey:$stringId"
  }
}

而我想为callServiceToFetchValues使用的函数需要IDCacheKey来获取Id,它看起来像这样。

private def getStringsFromLMS(cacheKeys: Seq[CacheKey]): Try[Map[CacheKey, String]] = { 
    cacheKeys.map(_ -> _.Id) 
}

因此它 returns 键 -> ID 的映射。问题是 batchCacheable 只能将 CacheKey 的 Seq 传递给它,但我需要它是 ID 的 IDCacheKey Seq。我该怎么做?

一个简单的解决方案是做这样的事情:

def getStringsFromLMS(cacheKeys: Seq[CacheKey]): Try[Map[CacheKey, String]] = { 
    cacheKeys.collect { case k: IDCacheKey => k.id } 
}

这将默默地忽略所有不是 IDCacheKey 的内容。如果您宁愿在输入中存在错误类型的键时抛出错误,只需将 .collect 替换为 .map.

无论如何,这都不是正确的解决方案。声明为 expect CacheKey 的函数应该能够处理 any CacheKey 的实例,无论是什么类型。

在更一般的层面上,没有提供足够的身份信息来获取值的 CacheKey 不是很有用。

长话短说,您的 CacheKey 特征似乎需要一个抽象的 id 方法。这将以自然(和“正确”)的方式解决您的问题。

或者,您可以进一步参数化 batchCacheable:

   def batchCacheable[T, K <: CacheKey](cacheKeys: Seq[K])(
      callServiceToFetchValues: Seq[K] => Try[Map[K, T]]
   ): Try[Map[K, T]] 

这让您声明 getStringsFromLMS 接受 IDCacheKey,并且仍然可以与 batchCacheable

一起使用