2017-03-11 2 views
0

J'ai le code ci-dessous et dans ma fonction findOrCreate(), j'obtiens une erreur disant Type mismatch found Unit, required Future[Customer]. La fonction customerByPhone() qui est appelée à l'intérieur findOrCreate() contient également des appels qui attendent Futures, ce qui explique pourquoi j'utilise un fatmap. Je ne sais pas pourquoi le résultat de la flatmap aboutit à Unit. Qu'est-ce que je fais mal?Type discordance trouvé Unité, requis Futur [Client] sur flatmap

override def findOrCreate(phoneNumber: String, creationReason: String): Future[AvroCustomer] = { 

    //query for customer in db 
    val avroCustomer: Future[AvroCustomer] = customerByPhone(phoneNumber).flatMap(_ => createUserAndEvent(phoneNumber, creationReason, 1.0)) 

} 

override def customerByPhone(phoneNumber: String): Future[AvroCustomer] = { 
    val query = Schema.Customers.byPhoneNumber(phoneNumber) 
    val dbAction: DBIO[Option[Schema.Customer]] = query.result.headOption 

    db.run(dbAction) 
    .map(_.map(AvroConverters.toAvroCustomer).orNull) 
} 

private def createUserAndEvent(phoneNumber: String, creationReason: String, version: Double): Future[AvroCustomer] = { 

    val query = Schema.Customers.byPhoneNumber(phoneNumber) 
    val dbAction: DBIO[Option[Schema.Customer]] = query.result.headOption 

    val data: JsValue = Json.obj(
    "phone_number" -> phoneNumber, 
    "agent_number" -> "placeholder for agent number", 
    "creation_reason" -> creationReason 
) 
    //empty for now 
    val metadata: JsValue = Json.obj() 

    //creates user 
    val avroCustomer: Future[AvroCustomer] = db.run(dbAction).map(_.map(AvroConverters.toAvroCustomer).orNull) 
    avroCustomer.onComplete({ 
    case Success(null) => { 

    } 

    //creates event 
    case Success(customer) => { 
     val uuid: UUID = UUID.fromString(customer.id) 
     //create event 
     val event: Future[CustomerEvent] = db.run(Schema.CustomerEvents.create(
     uuid, 
     "customer_creation", 
     version, 
     data, 
     metadata) 
    ).map(AvroConverters.toAvroEvent) 
    } 
    case Failure(exception) => { 

    } 
    }) 

    Future.successful(new AvroCustomer) 
} 
+0

Une instruction 'val' renvoie' Unit'. – Reactormonk

+0

@Reactormonk à ma connaissance, un val rend juste la variable immuable, mais vous pouvez retourner une valeur? – Rafa

+0

'val toto: Int = {val barre = 32}' vous donnera une erreur de compilation. – Reactormonk

Répondre

1

Alors que Reactormonk a répondu essentiellement ce dans les commentaires, je vais écrire en fait une réponse avec quelques détails. Son commentaire qu'une déclaration val produit Unit est fondamentalement correct, mais j'espère qu'un peu d'élaboration rendra les choses plus claires.

L'élément clé que je vois est que val est une déclaration. Les déclarations dans Scala sont des déclarations qui ne produisent pas de valeurs utiles. En raison de la nature fonctionnelle de Scala, ils produisent une valeur, mais c'est Unit et comme il n'y a qu'une seule instance de Unit, cela n'a aucune signification. La raison pour laquelle les programmeurs novices de Scala sont souvent tentés de faire quelque chose comme ça est qu'ils ne considèrent pas les blocs de code comme des instructions et sont souvent utilisés pour utiliser return dans d'autres langages. Alors considérons une fonction simplifiée ici. J'ai inclus un bloc de code car je pense que c'est la clé de cette erreur, même si elle n'est vraiment pas nécessaire ici. La valeur d'un bloc de code est simplement la valeur de la dernière expression dans le bloc de code. C'est pourquoi nous n'avons pas besoin de spécifier return, mais la plupart des programmeurs qui sont habitués à return sont un peu mal à l'aise avec cette expression nue à la fin d'un bloc. C'est pourquoi il est tentant de lancer la déclaration val.

def foo(i: Int): Int = { 
    val result = 42 * i // Error: type mismatch. 
} 

Bien sûr, comme cela a été mentionné, mais val résultats dans Unit ce qui en fait incorrect. Vous pouvez ajouter une ligne supplémentaire avec juste result, et cela va compiler, mais c'est trop verbeux et non-idiomatique. Scala prend en charge l'utilisation de return pour quitter une méthode/fonction et redonner une valeur particulière, bien que le nous soit généralement désapprouvé. En tant que tel, le code suivant fonctionne.

def foo(i: Int): Int = { 
    return 42 * i 
} 

Bien que vous ne devriez pas utiliser return dans le code Scala, je sens que l'imaginer être là peut aider à comprendre ce qui ne va pas ici. Si vous collez un return devant le val vous obtenez un code comme celui-ci.

def foo(i: Int): Int = { 
    return val result = 42 * i // Error: type mismatch. 
} 

Au moins pour moi, ce code est clairement incorrect. Le val est une déclaration et en tant que tel, il ne fonctionne tout simplement pas avec un return. Il faut un certain temps pour s'habituer au style fonctionnel des blocs en tant qu'expressions. Jusqu'à ce que vous arriviez à ce point, il pourrait aider juste à agir comme s'il y avait un return à la fin des méthodes sans en mettre un là.

Il est à noter que, dans les commentaires, jwvh prétend qu'une déclaration comme celle-ci dans C retournerait une valeur. C'est faux.Les affectations dans la plupart des langues de la famille C restituent la valeur affectée. a = 5 renvoie la valeur 5, mais pas les déclarations. Par conséquent, int a = 5; ne restitue rien et ne peut pas être utilisé comme expression.