2017-07-10 2 views
0

Voici un programme de strawman qui illustre la question que j'aiflux génériques et types de données abstraites

trait RequestBuilder { 
    type Out 

    def complete(p: Promise[Out]): Unit 
} 

def makeRequest(in: RequestBuilder): Source[(RequestBuilder, Promise[in.Out]), Future[in.Out]] = { 
    val p = Promise[in.Out] 

    Source.single(in -> p).mapMaterializedValue(_ => p.future) 
} 

val sink = MergeHub.source[(RequestBuilder, Promise[???])].to(Sink.foreach { 
    case (r, p) => r.complete(p) 
}).run() 

sink.runWith(makeRequest(new RequestBuilder { 
    type Out = Int 

    def complete(p: Promise[Out]): Unit = p.success(1) 
})) 

La question est, comment puis-je tapez le Promise[???] dans l'évier? Je suis en mesure de contourner ce problème en faisant la promesse d'une partie du trait RequestBuilder lui-même, mais cela me semble comme une odeur de code à

Répondre

0

Vous pouvez faire un alias de type pour le tuple:

type BuilderWithPromise[B <: RequestBuilder] = (B, Promise[B#Out]) 

ou une classe de cas:

case class BuilderWithPromise[B <: RequestBuilder)(
    builder: B, 
    promise: Promise[B#Out] 
) 

de toute façon devrait fonctionner

+0

Cela ne fonctionne pas vraiment, comme vous avez encore un paramètre de type. Si vous ne le fournissez pas, il sera déduit comme «Rien». Puisque 'Sink' ne sont pas covariants, cela vous empêchera de câbler quoi que ce soit – Jeff

+0

Vous ne savez pas exactement ce que vous dites. Pouvez-vous montrer votre code, et l'erreur que vous obtenez? – Dima

+0

Il y a un certain nombre de problèmes ci-dessus. Le premier est qu'il utilise la projection de type, ce qui ne fonctionne pas dans ce cas car j'ai besoin du type dépendant du chemin. L'autre est que l'alias de type et la classe de cas ont toujours un type paramétrique qui doit être connu au moment de la compilation. – Jeff