我是Scala类型系统的新手,我正试图通过这个JAXB编组示例来探索它。如果您将参数的类型从toString更改为AnyRef,它就会起作用。然而,我想通过类型系统表示,toString的参数必须与具体构造函数的类型参数相同。有办法做到这一点吗?
我不明白为什么下面的错误消息似乎指示typ=XMLMarshaller[TestObj]而不仅仅是TestObj。在我的调试器中,typ=TestObj。我们非常感谢您对这段代码的任何具体问题或见解的帮助!
error: type mismatch; found : TestObj required: _1.typ where val
_1: XMLMarshaller[TestObj]
val o = new XMLMarshaller[TestObj]().toString(new TestObj("hello","world"))
这是代码,只需粘贴到REPL:
import javax.xml.bind.{Marshaller, JAXBContext}
import java.io.{ByteArrayInputStream, StringWriter}
import org.jboss.resteasy.plugins.providers.jaxb.json.JettisonMappedContext
import javax.xml.bind.annotation.{XmlRootElement, XmlAccessorType, XmlAccessType}
abstract class XMarshaller {
val context:JAXBContext
type typ <: AnyRef
def toString(obj:typ): String = {
val marshaller:Marshaller = context.createMarshaller()
val sw = new StringWriter
marshaller.marshal(obj, sw)
sw.toString
}
def valueOf(xmlString:String): typ = {
val marshaller = context.createUnmarshaller()
marshaller.unmarshal(new ByteArrayInputStream(xmlString.getBytes())).asInstanceOf[typ]
}
}
class XMLMarshaller[T](implicit mT:Manifest[T]) extends XMarshaller {
val typ = mT.erasure
val context = JAXBContext.newInstance(typ)
}
class JSONMarshaller[T](implicit mT:Manifest[T]) extends XMarshaller {
val typ = mT.erasure
val context = new JettisonMappedContext(typ)
}
@XmlRootElement
@XmlAccessorType(value = XmlAccessType.FIELD)
case class TestObj(x:String, y:String){
def this() {this("","")}
}
object Test {
def main(args: Array[String]) {
val o = new XMLMarshaller[TestObj]().toString(new TestObj("hello","world"))
println(o)
}
}
由于Scala的语法工作方式,类可以具有类型成员和值具有相同名称的成员,并且不创建任何名称冲突(您可以始终根据上下文判断其含义)。
你所拥有的类似于:
abstract class FooAbstract {
type Type <: AnyRef
}
class FooConcrete[T<:AnyRef](implicit mt: Manifest[T]) extends FooAbstract {
val Type = mt.erasure
}
其中CCD_ 1不覆盖类型成员CCD_。你真的想要
class FooConcrete[T<:AnyRef](implicit mt: Manifest[T]) extends FooAbstract {
type Type = T
}
奇怪的是,Scala允许您无法覆盖类型,并且让它完全抽象。我不确定这是故意的还是Scala程序错误