2012-03-15 2 views
1

Я новичок в системе типа Scala, и я пытаюсь изучить ее с помощью примера JAXB Marshalling. Он работает, если вы измените тип параметра toString на AnyRef. Однако я хотел бы выразить через систему типов, что параметр toString должен быть того же типа, что и параметр type для конкретного конструктора. Есть ли способ достичь этого?Система типа Scala - помогает понять несоответствие по типу псевдонима

Не понимаю, почему приведенное ниже сообщение об ошибке указывает на то, что 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")) 

Вот код, просто вставьте в РЕПЛ:

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) 
    } 
} 

ответ

2

Из-за того, как синтаксис работает в Scala класс может иметь элемент типа и элемент значение с тем же именем, и не создает каких-либо name conflits (вы всегда можете указать ).

Что вы имеете аналогично:

abstract class FooAbstract { 
    type Type <: AnyRef 
} 

class FooConcrete[T<:AnyRef](implicit mt: Manifest[T]) extends FooAbstract { 
    val Type = mt.erasure 
} 

где FooConcrete не перекрывает тип элемента Type. Вы на самом деле хотите

class FooConcrete[T<:AnyRef](implicit mt: Manifest[T]) extends FooAbstract { 
    type Type = T 
} 

Любопытно, что Scala позволяет не переопределить тип, и оставить его полностью абстрактным. Я не уверен, что это намеренно или ошибка Scala .

+0

Оуэн, спасибо за помощь. Тем не менее, для меня все еще есть загадка. Во-первых, valueOf возвращал правильный тип, даже если подразумевается ваше объяснение, что конкретный тип val не был переопределен абстрактным типом типа. Как это возможно? – scalapeno

+0

Я не уверен. Наверное, вы имеете в виду правильный тип времени выполнения? Это не так удивительно, потому что тип выполнения не зависит от переменных типа. Я не уверен в том, почему предел 'asInstanceOf [typ]' преуспел. Вероятно, потому, что он передал его в «AnyRef», т. Е. Ничего не делал. – Owen

Смежные вопросы