scala 类型问题:SoftReference、ReferenceQueues、SoftHashMap

发布于 2024-10-19 07:42:24 字数 858 浏览 1 评论 0 原文

编辑 到目前为止,大多数答案都集中在我错误地扩展了 Map 的事实。我已在示例代码中更正了这一点,但类型问题仍然存在,问题仍然存在。

我正在尝试在 Scala 中实现 SoftHashMap,但遇到了类型不匹配的 问题错误:

inferred type arguments [K,V] do not conform to class SoftValue's type parameter bounds [K,+V <: AnyRef]
val sv = new SoftValue(kv._1, kv._2, queue)

我知道我过度限制了类型,但我不知道如何修复它。

import scala.collection.mutable.{Map, HashMap}    
import scala.ref._

class SoftValue[K, +V <: AnyRef](val key:K, value:V, queue:ReferenceQueue[V]) extends SoftReference(value, queue)

class SoftMap[K, V] extends Map[K, V]
{
  private val map = new HashMap[K, SoftValue[K, V]]

  private val queue = new ReferenceQueue[V]

  override def +=(kv: (K, V)):this.type =
  {
    val sv = new SoftValue(kv._1, kv._2, queue)
    map(kv._1) = sv
    this
  }
}

EDIT Most answers thus far are focusing on the fact that I was incorrectly extending Map. I have corrected this in the example code, but the type woes persist, and the question still stands.

I'm trying to implement a SoftHashMap in Scala, but am running into a type mismatch error:

inferred type arguments [K,V] do not conform to class SoftValue's type parameter bounds [K,+V <: AnyRef]
val sv = new SoftValue(kv._1, kv._2, queue)

I understand that I'm over-constraining the types, but I am not sure how to fix it.

import scala.collection.mutable.{Map, HashMap}    
import scala.ref._

class SoftValue[K, +V <: AnyRef](val key:K, value:V, queue:ReferenceQueue[V]) extends SoftReference(value, queue)

class SoftMap[K, V] extends Map[K, V]
{
  private val map = new HashMap[K, SoftValue[K, V]]

  private val queue = new ReferenceQueue[V]

  override def +=(kv: (K, V)):this.type =
  {
    val sv = new SoftValue(kv._1, kv._2, queue)
    map(kv._1) = sv
    this
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我很OK 2024-10-26 07:42:24

这样就可以编译了。 (编辑:我最初添加了val value,但这创建了一个强引用)。不确定您要如何处理迭代器...

import scala.collection.mutable.{Map, HashMap}    
import scala.ref._

class SoftValue[K, +V <: AnyRef](val key:K, value:V, 
  queue:ReferenceQueue[V]) extends SoftReference(value, queue)

class SoftMap[K, V <: AnyRef] extends Map[K, V] {
  private val map = new HashMap[K, SoftValue[K, V]]
  private val queue = new ReferenceQueue[V]

  def +=(kv: (K, V)): this.type = {
    val sv = new SoftValue(kv._1, kv._2, queue)
    map(kv._1) = sv
    this
  }

  def -=(k: K): this.type = { map -= k; this }
  def get(k: K) = map.get(k).flatMap(_.get)
  def iterator: Iterator[(K,V)] = error("todo")
}

定义 SoftMap 时缺少 V <: AnyRef,因此 V 可以用作 SoftValue 构造函数的参数。

This compiles. (edit: I initially added val value but that created a strong reference). Not sure how you want to handle iterator...

import scala.collection.mutable.{Map, HashMap}    
import scala.ref._

class SoftValue[K, +V <: AnyRef](val key:K, value:V, 
  queue:ReferenceQueue[V]) extends SoftReference(value, queue)

class SoftMap[K, V <: AnyRef] extends Map[K, V] {
  private val map = new HashMap[K, SoftValue[K, V]]
  private val queue = new ReferenceQueue[V]

  def +=(kv: (K, V)): this.type = {
    val sv = new SoftValue(kv._1, kv._2, queue)
    map(kv._1) = sv
    this
  }

  def -=(k: K): this.type = { map -= k; this }
  def get(k: K) = map.get(k).flatMap(_.get)
  def iterator: Iterator[(K,V)] = error("todo")
}

You're missing V <: AnyRef when defining SoftMap, so that V can be used as argument of the SoftValue constructor.

太傻旳人生 2024-10-26 07:42:24

正如 Sam 指出的,第一个问题是您正在扩展 scala.collection.immutable.Map ,您通过别名 scala.Map 访问它。

其次,您已将 V 声明为协变类型参数。这意味着 SoftMap[String, Dog]SoftMap[String, Any] 的子类型。在类定义中的逆变位置引用协变类型参数是无效的。

trait Contra[+A] {
    def a: A    // method return type is a covariant position, okay
    def m(a: A) // method parameter is a contravariant position, error
    def n[AA >: A](a: AA) // upper bound of a type param is in covariant position, okay
}

类型安全的可变集合需要在同变和逆变位置引用元素类型:分别检索元素和添加元素。因此,它们必须将类型参数声明为不变的。

collection.mutable.Map 的定义表明了这一点:

trait Map[A, B] 
  extends Iterable[(A, B)]
     with scala.collection.Map[A, B] 
     with MapLike[A, B, Map[A, B]]

如果你扩展它,你会被告知:

scala> trait SoftMap[K, +V] extends collection.mutable.Map[K, V]
<console>:25: error: covariant type V occurs in invariant position in type [K,+V]java.lang.Object with scala.collection.mutable.Map[K,V] of trait SoftMap
       trait SoftMap[K, +V] extends collection.mutable.Map[K, V]
             ^

另一方面:

scala> trait SoftMap[K, V] extends collection.mutable.Map[K, V]
defined trait SoftMap

Sam 也指出的最后一个问题是方法 +做你想做的事情,至少从 Scala 2.8 开始。您应该实现 方法+=

First problem, as pointed out by Sam, is that you are extending scala.collection.immutable.Map, which you are accessing through the alias scala.Map.

Second, you have declared V as a covariant type parameter. This would mean that a SoftMap[String, Dog] is a subtype of SoftMap[String, Any]. It is not valid to refer to the covariant type parameter in a contravariant position in the class definition.

trait Contra[+A] {
    def a: A    // method return type is a covariant position, okay
    def m(a: A) // method parameter is a contravariant position, error
    def n[AA >: A](a: AA) // upper bound of a type param is in covariant position, okay
}

Typesafe mutable collections need to refer to the element type in both co- and contravariant positions: to retrieve elements and to add elements respectively. For this reason, they must declare the type parameter as invariant.

The definition of collection.mutable.Map shows this:

trait Map[A, B] 
  extends Iterable[(A, B)]
     with scala.collection.Map[A, B] 
     with MapLike[A, B, Map[A, B]]

If you extend this, you will be told:

scala> trait SoftMap[K, +V] extends collection.mutable.Map[K, V]
<console>:25: error: covariant type V occurs in invariant position in type [K,+V]java.lang.Object with scala.collection.mutable.Map[K,V] of trait SoftMap
       trait SoftMap[K, +V] extends collection.mutable.Map[K, V]
             ^

On the other hand:

scala> trait SoftMap[K, V] extends collection.mutable.Map[K, V]
defined trait SoftMap

The final issue, also pointed out by Sam, is that the method + doesn't do what you intend, at least since Scala 2.8. You should implement the method +=.

您的好友蓝忘机已上羡 2024-10-26 07:42:24

如果 SoftMap 是可变的,那么您无法使用其值类型 V 的超类型 V1 来更新它。如果可能的话,旧映射将绑定到值为 V1 类型的键值对,并且旧映射的类型为 V。在旧映射中查找新绑定时,这会导致类型错误。

可变映射通过复制映射来实现+,不可变映射具有更高效的+。另一方面,可变映射具有 += ,它会修改现有映射并且效率更高。 += 的参数是一个键和一个值,其中值不是映射值类型的超类型。

在这种情况下,解决方案是复制地图。

编辑:

更改上述问题后收到的错误消息是由于软映射的类型参数 V 可以是任何类型,而类型 V SoftValue 的 code> 必须是 AnyRef 的子类型(不能是 IntFloat,即是 AnyVal 的子类型)。因此,您无法从 SoftMap 创建类型为 VSoftValue,因为有人可能会通过以下方式实例化 SoftMap:将 V 设置为 Int

If SoftMap is going to be mutable, then you cannot update it with a supertype V1 of it's value type V. If that were possible, the old map would have a binding to a key-value pair with a value of type V1, and the type of the old map is V. This would result in type errors when looking up the new binding in the old map.

Mutable maps implement + by copying the map, immutable maps have a more efficient +. On the other hand, mutable maps have += which modifies the existing map and is more efficient. The argument of += is a key and a value, where a value isn't the supertype of the map value type.

In this case, the solution is to copy the map.

EDIT:

The error message you've got after changing the question above is due to the fact that the type parameter V of the soft map can be any type whatsoever, while the type V of the SoftValue has to be a subtype of AnyRef (cannot be an Int or a Float, that is, a subtype of AnyVal). Therefore, you cannot create a SoftValue with the type V from the SoftMap, because someone might instantiate the SoftMap by setting the V to, say Int.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文