使用谷歌Guava的CacheBuilder出现Scala 2.10类型不匹配错误

4
我正在为我的几个实体编写通用缓存,使用的是Scala 2.10.1。目前,由于Scala生态系统中的选项不多,我正在使用谷歌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

最好代码片段在语法上是正确的。你代码中连续的两个句号(.)无法编译。此外,你的代码_暗示_但并没有明确说明KE是某个封闭结构中的类型参数限定。你能否纠正和完善代码片段,以便其他人可以复制和修改你的原始代码? - Randall Schulz
抱歉。已更新代码并包含类声明。 - adivis
2个回答

3

CacheBuilder需要一个Object/AnyRef类型的参数。您可以按照以下方式使用java.lang.Long代替scala.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]

2

如果您不介意一点丑陋的代码,那么您可以让它起作用。主要问题在于CacheBuilder上的build函数返回一个与类型[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]

我试过了,得到了第二个错误。更新了问题以反映相同的情况。我认为如果我将类型边界设置为<:Object,那么几乎所有的anyval都是被禁止的,这不是我想要的。 - adivis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接