发现单元类型不匹配,平面图上需要 Future[Customer]
Type mismatch found Unit, required Future[Customer] on flatmap
我有以下代码,在我的 findOrCreate()
函数中,我收到一条错误消息 Type mismatch found Unit, required Future[Customer]
。在 findOrCreate()
内部调用的 customerByPhone()
函数也包含期望 Futures 的调用,这就是我使用 fatmap 的原因。我不知道为什么平面图的结果是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)
}
虽然 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
来留下 method/function 并返回一个特定的值,尽管 us 通常不受欢迎。因此,以下代码有效。
def foo(i: Int): Int = {
return 42 * i
}
虽然你不应该在 Scala 代码中使用 return
,但我觉得想象它在那里有助于理解这里的错误。如果你在 val
前面加上 return
,你会得到如下代码。
def foo(i: Int): Int = {
return val result = 42 * i // Error: type mismatch.
}
至少对我来说,这段代码显然是不正确的。 val
是一个声明,因此它不适用于 return
。习惯将块作为表达式的函数式风格需要一些时间。在你达到这一点之前,它可能会有所帮助,就像在方法末尾有一个 return
而不是实际放在那里。
值得注意的是,在评论中,jwvh 声称在 C 中这样的声明将 return 一个值。那是错误的。 Assignments 在大多数 C 系列语言中返回被赋值的值,因此 a = 5
returns 值 5
,但声明不会,所以 int a = 5;
不会返回任何东西,也不能用作表达式。
我有以下代码,在我的 findOrCreate()
函数中,我收到一条错误消息 Type mismatch found Unit, required Future[Customer]
。在 findOrCreate()
内部调用的 customerByPhone()
函数也包含期望 Futures 的调用,这就是我使用 fatmap 的原因。我不知道为什么平面图的结果是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)
}
虽然 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
来留下 method/function 并返回一个特定的值,尽管 us 通常不受欢迎。因此,以下代码有效。
def foo(i: Int): Int = {
return 42 * i
}
虽然你不应该在 Scala 代码中使用 return
,但我觉得想象它在那里有助于理解这里的错误。如果你在 val
前面加上 return
,你会得到如下代码。
def foo(i: Int): Int = {
return val result = 42 * i // Error: type mismatch.
}
至少对我来说,这段代码显然是不正确的。 val
是一个声明,因此它不适用于 return
。习惯将块作为表达式的函数式风格需要一些时间。在你达到这一点之前,它可能会有所帮助,就像在方法末尾有一个 return
而不是实际放在那里。
值得注意的是,在评论中,jwvh 声称在 C 中这样的声明将 return 一个值。那是错误的。 Assignments 在大多数 C 系列语言中返回被赋值的值,因此 a = 5
returns 值 5
,但声明不会,所以 int a = 5;
不会返回任何东西,也不能用作表达式。