2012-01-18 27 views
3

我對Scala很新穎,仍然不太瞭解泛型。因此,我無法弄清楚爲什麼編譯器恨我類型不匹配錯誤。在Scala中使用番石榴的簡單緩存管理器參數化(泛型)類型錯誤

我正在使用Google的Guava庫創建一些簡單的緩存,表示爲Scala的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()) 
//  }) 
    } 
} 

基本上,如果我嘗試添加番石榴緩存到緩存(通過註釋掉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

你能給出更多的解釋,說明哪部分失敗,以及如何做? – 2012-01-18 21:45:43

+0

是否......希望它有幫助! – Matthew 2012-01-18 22:59:50

+0

嗯,這讓我非常肯定,作爲一個不熟悉Scala的Guava開發者,這個問題不是我會理解的。 =/ – 2012-01-19 05:10:53

回答

3

檢索緩存時由於您提供的類型信息,這是沒有必要的嘗試和維持通配符輸入。將值輸入AnyRef然後在最後將類型轉換爲V要簡單得多。以下編譯和應該幫助。此外,不需要直接調用ascalaConcurrentMap,因爲它很好...隱式。

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構建的,我認爲你需要用某種方式來包裝它才能完成這項工作。但我只是一個番石榴開發者,因此,不是一個斯卡拉人。 – 2012-01-19 01:47:53

+0

Scala集合庫提供了許多從Java類型到Scala類型的隱式轉換。 asScalaConcurrentMap可以通過'import scala.collection.JavaConversions._'在任何時候遇到需要Scala的Java集合時使用,它會找到正確的隱式方法來轉換它。 – 2012-01-19 05:43:35

+0

謝謝尼爾,工作!這樣一個明顯而簡單的解決方案,我不知道爲什麼我沒有想到它...... – Matthew 2012-01-19 14:20:52