4

scala 2.10.1 でいくつかのエンティティの汎用キャッシュを作成しています。今のところ、scala エコシステムには多くのオプションがないため、Google Guava の CacheBuilder を使用しています。

コード:

trait CachedEntity[E <: KeyedEntity[K],K] {

  def lookup(id:K):E

  def getElem(id:K):Option[E] = Try(elemCache.get(id)).toOption

  val elemCache = CacheBuilder.newBuilder().maximumSize(10).expireAfterWrite(1,TimeUnit.MINUTES).build(
    new CacheLoader[K,E] {
      def load(key:K) = {
        println("Looking Up key:" + key + "in Class:" + this.getClass.getName)
        lookup(key)
      }
    }
  )
}
trait LongKeyed[E<: KeyedEntity[Long],Long] extends CachedEntity[E,Long]

ただし、sbt はエラーをスローします。

[error] KEHCaching.scala:16: type mismatch;
[error]  found   : id.type (with underlying type K)
[error]  required: Object with K
[error]   def getElem(id:K):Option[E] = Try(elemCache.get(id)).toOption
[error]                                                   ^
[error] one error found

何か案は?K<:Object を次のように追加しても:

trait CachedEntity[E <: KeyedEntity[K],K <:Object] {

このエラーが発生します

[error] KEHCaching.scala:27: type arguments [E,Long] do not conform to trait CachedEntity's type parameter bounds [E <: org.squeryl.KeyedEntity[K],K <: Object]
[error] trait LongKeyed[E<: KeyedEntity[Long],Long] extends CachedEntity[E,Long]
[error]                                                     ^
[error] one error found
4

2 に答える 2

3

CacheBuilder には Object/AnyRef が必要です。次のように、scala.Long の代わりに java.lang.Long を使用できます。Scala は、必要に応じて自動的にボックス化/ボックス化解除します。

import scala.util.Try
import java.util.concurrent.TimeUnit
import java.lang.{Long => JLong}

trait KeyedEntity[K]

trait CachedEntity[E <: KeyedEntity[K], K <: AnyRef] {

  def lookup(id:K):E

  def getElem(id:K):Option[E] = Try(elemCache.get(id)).toOption

  val elemCache = CacheBuilder.newBuilder().maximumSize(10).expireAfterWrite(1,TimeUnit.MINUTES).build(
    new CacheLoader[K,E] {
      def load(key:K) = {
        println("Looking Up key:" + key + "in Class:" + this.getClass.getName)
        lookup(key)
      }
    }
  )
}

trait LongKeyed[E <: KeyedEntity[JLong]] extends CachedEntity[E,JLong]
于 2013-08-02T01:37:55.617 に答える
2

少し醜いキャストが気にならない場合は、これを機能させることができます。主な問題は、build関数 onCacheBuilderが types に関連付けられたキャッシュを返すことです[Object,Object]。Scala では、AnyValは Object から派生していないため、機能しません。しかし、次のコード サンプルをモックアップして、この制限を回避する方法を示します。

trait CachedEntity[E <: KeyedEntity[K], K] {

  def lookup(id:K):E

  def getElem(id:K):Option[E] = Try(elemCache.get(id)).toOption

  val elemCache = CacheBuilder.newBuilder().build(
    new CacheLoader[K,E] {
      def load(key:K) = {
        println("Looking Up key:" + key + "in Class:" + this.getClass.getName)
        lookup(key)
     }
    }
  ).asInstanceOf[LoadingCache[K,E]]
}

trait LongKeyed[E<: KeyedEntity[Long]] extends CachedEntity[E,Long]

case class MyEntity(id:Long, value:String) extends KeyedEntity[Long]

class MyEntityCache extends LongKeyed[MyEntity]{
  def lookup(id:Long) = MyEntity(id, "foo") 
}

object CachedEntityTest{
  def main(args: Array[String]) {
    val cache = new MyEntityCache
    val entity = cache.getElem(1)
    println(entity)
  }
}

//Faking this for purposes of code sample...
trait KeyedEntity[K]
于 2013-04-25T00:41:00.173 に答える