2012-01-18 10 views
3

私はScalaにはかなり新しく、よくジェネリックスをよく理解していません。その結果、コンパイラが型の不一致エラーで私を嫌にする理由を理解できません。ScalaでGuavaを使用しているシンプルなキャッシュマネージャー(ジェネリック)型エラー

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

このうちどの部分が失敗し、どのように説明できますか? –

+0

それは...それが助けてくれることを願った! – Matthew

+0

これは、Scalaに慣れていないGuava開発者として、私が理解することができない問題であることを私にかなり確かめています。 =/ –

答えて

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はScalaではなく、Javaのために作られています。私は、あなたがその作業をするために何らかの方法でそれをラップする必要があると思います。しかし、私はGuavaの開発者なので、Scalaの人ではありません。 –

+0

Scalaコレクションライブラリは、Java型からScala型への多くの暗黙的な変換を提供します。 asScalaConcurrentMapは 'scala.collection.JavaConversions._'を介して利用できます。これは、Javaコレクションに遭遇したときにScalaが必要な場合に、変換するための暗黙的なメソッドが見つかる場所です。 –

+0

ありがとうNeil、それは働いた!そのような明白でシンプルな解決策は、私はなぜそれについて考えるのか分かりません... – Matthew

関連する問題