【问题标题】:Scala type system - help understanding mismatch on type aliasScala 类型系统 - 帮助理解类型别名的不匹配
【发布时间】:2012-03-16 04:03:55
【问题描述】:

我是 Scala 类型系统的新手,我正在尝试通过这个 JAXB Marshalling 示例来探索它。如果将参数的类型从 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 types


    【解决方案1】:

    由于 Scala 的语法是如何工作的,一个类可以有类型成员和值 具有相同名称的成员,并且不创建任何名称冲突(您始终可以 通过上下文来判断是什么意思)。

    你所拥有的类似于:

    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 错误。

    【讨论】:

    • 欧文,感谢您的帮助。不过,对我来说,这里仍然有一些谜团。首先, valueOf 正在返回正确的类型,即使您的解释的含义是具体的 val 类型没有覆盖抽象类型的类型。这怎么可能?
    • 我不确定。我猜你的意思是正确的运行时类型?这并不奇怪,因为运行时类型不受类型变量的影响。我不确定的是为什么演员asInstanceOf[typ] 成功了。可能是因为它将其转换为AnyRef,即什么也没做。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-30
    • 2012-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多