类型不匹配找到单位,需要在flatmap上的未来[客户]

时间:2017-03-11 22:29:58

标签: scala functional-programming future flatmap

我有以下代码,在我的findOrCreate()函数中,我收到错误Type mismatch found Unit, required Future[Customer]。在customerByPhone()内调用的findOrCreate()函数也包含期望Futures的调用,这就是我使用fatmap的原因。我不知道为什么flatmap的结果导致Unit。我做错了什么?

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)
}

1 个答案:

答案 0 :(得分:1)

虽然Reactormonk在评论中基本上回答了这个问题,但我真的会写一些带有一些细节的答案。他对val声明产生Unit的评论从根本上说是正确的,但我希望通过一些细化可以使事情变得更加清晰。

我看到的关键元素是val是一个声明。 Scala中的声明是不能产生有用值的声明。由于Scala的功能特性,它们确实产生了一个值,但它是Unit,因为Unit只有一个实例,所以它没有任何含义。

Scala新手的程序员经常想做这样的事情的原因是他们没有将代码块视为语句,并且经常习惯在其他语言中使用return。所以我们在这里考虑一个简化的功能。

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

我包含一个代码块,因为我认为这是此错误的关键,尽管此处并不需要。代码块的值只是代码块中最后一个表达式的值。这就是为什么我们不必指定return,但是大多数习惯于return的程序员在块结束时对这个裸表达式有点不舒服。这就是为什么抛出val声明很有诱惑力。

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

当然,如前所述,val导致Unit导致此错误。你可以添加一个只有result的额外行,这将编译,但它过于冗长和非惯用。

Scala支持使用return来保留一个方法/函数并返回一个特定的值,尽管我们通常不赞成。因此,以下代码可以正常工作。

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

虽然你不应该在Scala代码中使用return,但我觉得想象它在那里可以帮助理解这里的错误。如果您在return前面加val,则可获得如下代码。

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

至少对我来说,这段代码显然不正确。 val是一个声明,因此它不能与return一起使用。需要一些时间来习惯块的功能样式作为表达式。在你达到这一点之前,可能只是在方法结束时表现得像return而没有实际放在那里。

值得注意的是,在评论中,jwvh声称在C中这样的声明会返回一个值。那是错误的。大多数C系列语言中的作业会返回已分配的值,因此a = 5会返回值5,但声明不会发生,{{1} }不会回馈任何东西,也不能用作表达。