Scala ClassManifest instead of Type[T]
The following code
def httpPost[T: ClassManifest](data: AnyRef): T = {
val webResource = client.resource("http://localhost..")
val resp = webResource.post(classOf[ClientResponse], data)
resp.getEntity(classManifest[T].erasure) //Need classOf[T] here
}
results in this type mismatch compilation error
[INFO] found : _$1 whe开发者_StackOverflow社区re type _$1
[INFO] required: T
[INFO] resp.getEntity(classManifest[T].erasure)
Based on the answer to Scala classOf for type parameter it looks like it should work.
The erasure method returns java.lang.Class[_] and I presume that this is the problem so I have two questions:
- Why does the class manifest return an existential type and not simply Class[T] - if it's the erasure of T, surely that will always be _ (underscore) because T is obviously unknown, which means its return value isn't as useful as I'd have expected.
- What do I need to do to make the code work!
Update:
Thanks Kim and Jean-Phillipe for your answers.
I had previously tried a cast so the original last line was replaced with
val responseData = resp.getEntity(classManifest[T].erasure) //Runtime error
responseData.asInstanceOf[T]
and this compiles but there's now a runtime error because the getEntity method is passed the class of Object, which it can't process because it needs a more specific type (for which it has a handler). Although it's deferred until runtime, it again comes down to the erasure method not giving specific type information and that's why I thought that to solve the problem, the inline example must be solved.
There's something seriously wrong with this code. In particular:
def httpPost[T: ClassManifest](data: AnyRef): T = {
val webResource = client.resource("http://localhost..")
val resp = webResource.post(classOf[ClientResponse], data)
resp.getEntity(classManifest[T].erasure) //Need classOf[T] here
}
How is Scala supposed to know what the type of T
is? Are you passing it explicitly when invoking httpPost
? I suspect not, and that's the reason why erasure
is returning Object
for you.
As for why ClassManifest#erasure
returns Class[_]
instead of something else, I suspect the reason is that this is the type used by most Java methods, and since Class
is invariant, if erasure
returned Class[T]
, then you'd have to cast it to use it with those methods!
First question: No idea...
Second question: I think it is safe to cast here. You can use foo.asInstanceOf[Class[T]]
.
I believe that an existential type is returned to make it clear that the cast that you may want to make is your responsibility. Class
is a bit weird: for instance, a Class[List[String]]
should actually be typed as a Class[List[_]]
as it does not carry any information about the String
parametrization of List
. The cast suggested by Kim is always safe when T
is not itself a parametrized type.
精彩评论