简体   繁体   中英

implicit from context bound on collection type parameter

I have some code that streams a response by converting a Stream of case classes to json representations using spray.json. This works fine for a single case class, but I want to genericize it.

So I'm starting with case classes like this:

import spray.json._
import spray.json.DefaultJsonProtocol._
case class Item(foo: String, bar: Int)
case class Report(baz: String, stream: Stream[Item])
object Protocol { implicit val ItemFormat = jsonFormat2(Item) }

In my report streaming method I have code like this (highly simplified):

def streamReport(...) {
    import Protocol._

    val handler: PartialFunction[Try[Any], String] = {
        case Success(Report(_, stream)) =>
            stream.head.toJson.compactPrint
    }
}

What I'd like to do is genericize Report to support more than Item:

case class Report[T](baz: String, stream: Stream[T])

But now, of course, the streamReport method can't find a JsonWriter in scope for type Any .

I can do something close to what I want if I add a type parameter with context bound to streamReport , and pass in the Report directly:

def jsonStream[T : JsonWriter](report: Report[T]): String = 
    implicitly[JsonWriter[T]].write(report.stream.head).compactPrint

However, I cannot figure out how to get this to work with the PartialFunction . The following does not compile (and wouldn't fit exactly anyway as the signature of the partial function is different than above):

def handler[T : JsonWriter](): PartialFunction[T, String] = {
    case Success(Report(_, stream)) =>
        implicitly[JsonWriter[T]].write(report.stream.head).compactPrint
}

I'm not sure where it's going wrong. Does it have to do with type erasure, or a problem with having Try[Any] as the parameter type on my partial function? How can I get the implicit JsonWriter I need for the element type of the stream?

My guess is that Any is not the problem, the problem is trying to match case Success(Report(_, stream)) , after the definition for Report is now Report[T] .

Also, in order to find the right implicit conversion, the compiler needs to understand the type involved (in compile time). Try using something like this:

def streamReport[T](...) {
    import Protocol._

    val handler: PartialFunction[Try[Any], String] = {
        case Success(Report[T](_, stream)) =>
            stream.head.toJson.compactPrint
    }
}

That way, the compiler will know what is being matched, and can infer the right type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM