Nyc*_*cto 0 generics scala map
我正在尝试编写一个小的包装类,以使Gson库更加友好.不幸的是,当我试图按照我想要的方式进行此操作时,我遇到了编译错误.
这是我到目前为止的代码:
package com.test
import com.google.gson.{JsonObject, JsonElement}
import scala.collection.Iterator
import scala.collection.immutable.Map
case class GsonMap ( private val inner: JsonObject = new JsonObject )
extends Map[String, JsonElement] {
/** {@inheritDoc} */
override def iterator: Iterator[(String, JsonElement)]
= new Iterator[(String, JsonElement)] {
private val entries = inner.entrySet.iterator
override def hasNext: Boolean = entries.hasNext
override def next: (String, JsonElement) = {
val elem = entries.next
( elem.getKey, elem.getValue )
}
}
/**
* Returns a clone of the inner JsonObject
*/
private def cloneInner: JsonObject = {
val result = new JsonObject()
iterator.foreach { (item) => result.add( item._1, item._2 ) }
result
}
/** {@inheritDoc} */
override def + ( kv: (String, JsonElement) ): GsonMap = {
val cloned = cloneInner
cloned.add( kv._1, kv._2 )
GsonMap( cloned )
}
/** {@inheritDoc} */
override def get( key: String ): Option[JsonElement]
= Option( inner.get(key) )
/** {@inheritDoc} */
override def - ( key: String ): GsonMap = {
val cloned = cloneInner
cloned.remove( key )
GsonMap( cloned )
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我知道该+方法与Map类中定义的方法不匹配.真的,这就是问题所在.我希望+方法接受JsonElements并返回a GsonMap,但我不确定如何使其工作.我在这一点上尝试了一些变化,但没有运气
作为参考,这是我收到的编译错误:
[info] Compiling 1 Scala source to target/scala-2.9.2/classes...
[error] src/main/scala/GsonMap.scala:7: class GsonMap needs to be abstract, since method + in trait Map of type [B1 >: com.google.gson.JsonElement](kv: (String, B1))scala.collection.immutable.Map[String,B1] is not defined
[error] case class GsonMap ( val inner: JsonObject = new JsonObject )
[error] ^
[error] src/main/scala/GsonMap.scala:31: method + overrides nothing
[error] override def + ( kv: (String, JsonElement) ): GsonMap = {
[error] ^
[error] two errors found
Run Code Online (Sandbox Code Playgroud)
有关于此的任何建议吗?
更新:
正如下面的建议,这是我尝试过的变种之一:
override def +[T >: JsonElement] ( kv: (String, T) ): GsonMap = {
val cloned = cloneInner
cloned.add( kv._1, kv._2 )
GsonMap( cloned )
}
Run Code Online (Sandbox Code Playgroud)
但是,它也失败了:
[info] Compiling 1 Scala source to target/scala-2.9.2/classes...
[error] /src/main/scala/GSON.scala:33: type mismatch;
[error] found : T
[error] required: com.google.gson.JsonElement
[error] cloned.add( kv._1, kv._2 )
[error] ^
[error] one error found
Run Code Online (Sandbox Code Playgroud)
我对>:运算符的理解是T必须是JsonElement的父级,我认为这不是我正在寻找的.在这种情况下,此映射只能包含JsonElements的实例,因此放入JsonElements的父项是不合适的.
您的错误的直接原因是您+只接受JsonElement,而+trait期望一个类型参数的上限为JsonElement.
override def +[T >: JsonElement] ( kv: (String, T) ): GsonMap = {
val cloned = cloneInner
cloned.add( kv._1, kv._2 )
GsonMap( cloned )
}
Run Code Online (Sandbox Code Playgroud)
原因是(正如在@Frank的回答中所指出的),Map在其值参数中是协变的,即如果Child是子类型Parent,Map[String,Parent]则将是超类型Map[String, Child],并且此add定义允许您"向上添加"到Map:
scala> class Element;
defined class Element
scala> class SubElement extends Element;
defined class SubElement
scala> val m = Map("foo"-> new SubElement)
m: scala.collection.immutable.Map[java.lang.String,SubElement] = Map(foo -> SubElement@6a63afa4)
scala> m + ("bar" -> new Element)
res0: scala.collection.immutable.Map[java.lang.String,Element] = Map(foo -> SubElement@2e7ff81e, bar -> Element@654ab15b)
scala> m + ("bar" -> new Element) + ("baz" -> "Text")
res1: scala.collection.immutable.Map[java.lang.String,java.lang.Object] = Map(foo -> SubElement@6a63afa4, bar -> Element@233d0d04, baz -> Text)
Run Code Online (Sandbox Code Playgroud)
如果你试图Map在一个可变的支持对象上实现不可变的特征,你必须自己提供这个"up-casting",或者你可以放弃Scala标准库的热情拥抱,而是扩展mutable.Map,已经做了正是为了你.如果您的Java类型实现了java.util.Map接口,那么甚至还有现成的包装器和隐式转换scala.collection.JavaConversions.
我不知道你要用你的自定义做什么Map,但很可能扩展Map不是完全可行的方式(在标准介绍中将地图扩展到Scala集合库的例子实现了一个新数据您希望在大多数代码中处理Scala映射,然后提供隐式,例如将Map转换为边界处的GSON等效值.
| 归档时间: |
|
| 查看次数: |
1366 次 |
| 最近记录: |