2012-01-18 1 views
3

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

Я использую библиотеку Гуавы Google для создания некоторых простых кешей, представленных как ConcurrentMap от Scala. Я хотел бы отслеживать созданные кэши, используя другую карту имени кэша для 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, { 
+0

Можете ли вы дать больше объяснений относительно того, в какой части этого не удается и как? –

+0

Сделал это ... Надеюсь, это поможет! – Matthew

+0

Ну, это делает меня довольно уверенным, что, как разработчик Guava, незнакомый с Scala, проблема не та, которую я пойму. =/ –

ответ

3

Поскольку вы предоставляете информацию о типе при извлечении кэша, не нужно пытаться поддерживать подстановочные печатать. Гораздо проще вводить значения в 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]] 
} 
+0

Является ли это неявным? Guava построен для Java, а не Scala, и я думаю, вам нужно каким-то образом обернуть его, чтобы сделать эту работу. Но я всего лишь разработчик Guava и, следовательно, не человек Scala. –

+0

Библиотека коллекции Scala предоставляет множество неявных преобразований из типов Java в типы Scala. asScalaConcurrentMap становится доступным через 'import scala.collection.JavaConversions._' с тех пор в любое время, когда встречается коллекция Java, где требуется Scala, он находит правильный неявный метод для его преобразования. –

+0

Спасибо Нейлу, что сработало! Такое явное и простое решение, я понятия не имею, почему я не думал об этом ... – Matthew

Смежные вопросы