Простой менеджер кеша, использующий Guava в Scala параметризованный (обобщенный) тип ошибки - PullRequest
3 голосов
/ 18 января 2012

Я довольно новичок в Scala и до сих пор не очень хорошо понимаю дженерики. Следовательно, я не могу понять, почему компилятор ненавидит меня из-за ошибок несоответствия типов.

Я использую библиотеку Google Guava для создания простых кешей, представленных в виде Scur's ConcurrentMap. Я хотел бы отслеживать созданные кэши, используя другую карту имени кэша для ConcurrentMap (кеш). Вот что я до сих пор собираю, но отсутствует отслеживание кэшей (я закомментировал биты, которые не работают):

import scala.collection.mutable.ConcurrentMap

trait CacheManager {

    def getCache[V <: AnyRef](
            cacheName: String,
            cacheListener: Option[CacheListener] = None): ConcurrentMap[String, V]

}


import scala.collection.JavaConversions._
import com.google.common.collect.MapMaker
import java.util.concurrent.{ConcurrentMap => JConcurrentMap, TimeUnit}
import org.slf4j.LoggerFactory
import com.google.common.cache.{RemovalNotification, RemovalListener, CacheBuilder}
import scala.collection.mutable.ConcurrentMap

class LocalCacheManager extends CacheManager {

    private val logger = LoggerFactory.getLogger(classOf[LocalCacheManager])


    private val caches /*: ConcurrentMap[String, ConcurrentMap[String, _ <: AnyRef]]*/ =
            asScalaConcurrentMap[String, ConcurrentMap[String, _ <: AnyRef]](
                new MapMaker().concurrencyLevel(4).makeMap[String, ConcurrentMap[String, _ <: AnyRef]]())

    def getCache[V <: AnyRef](cacheName: String, cacheListener: Option[CacheListener] = None) = {
//        caches.getOrElseUpdate(cacheName, {
            val cache = CacheBuilder.newBuilder()
                        .concurrencyLevel(4)
                        .softValues()
                        .expireAfterAccess(30, TimeUnit.MINUTES)
                        .build[String, V]()
            asScalaConcurrentMap[String, V](cache.asMap())
//        })
    }
}

В основном, если я пытаюсь добавить кеш Guava к кешам (через закомментированный caches.getOrElseUpdate), то компилятор жалуется на следующее:

error: type mismatch;
found   : scala.collection.mutable.ConcurrentMap[String,_$1] where type _$1 <: AnyRef
required: scala.collection.mutable.ConcurrentMap[String,V]
caches.getOrElseUpdate(cacheName, {

1 Ответ

3 голосов
/ 19 января 2012

Поскольку вы предоставляете информацию о типе при извлечении кэша, нет необходимости пытаться поддерживать подстановочный тип. Гораздо проще ввести значения в AnyRef, а затем в конце привести тип к V. Следующие компиляции и должны помочь. Кроме того, нет необходимости напрямую вызывать asScalaConcurrentMap, поскольку он ... неявный.

import scala.collection.JavaConversions._
import com.google.common.collect.MapMaker
import java.util.concurrent.TimeUnit
import com.google.common.cache.CacheBuilder
import scala.collection.mutable.ConcurrentMap

trait CacheListener // not sure what this is doing yet.

trait CacheManager {

    def getCache[V <: AnyRef](
            cacheName: String,
            cacheListener: Option[CacheListener] = None): ConcurrentMap[String, V]

}

class LocalCacheManager extends CacheManager {
    private val caches: ConcurrentMap[String, ConcurrentMap[String, AnyRef]] =
                new MapMaker().concurrencyLevel(4).makeMap[String, ConcurrentMap[String, AnyRef]]()
    def getCache[V <: AnyRef](cacheName: String, cacheListener: Option[CacheListener] = None) = 
      caches.getOrElseUpdate(cacheName, {
              CacheBuilder.newBuilder()
                          .concurrencyLevel(4)
                          .softValues()
                          .expireAfterAccess(30, TimeUnit.MINUTES)
                          .asInstanceOf[CacheBuilder[String, AnyRef ]]
                          .build[String, AnyRef ]()
                          .asMap()
              }).asInstanceOf[ConcurrentMap[String, V]]
}
...