MVar tryPut returns true 和 isEmpty 也 returns true
MVar tryPut returns true and isEmpty also returns true
我写了简单的回调(处理程序)函数,我传递给异步 api 我想等待结果:
object Handlers {
val logger: Logger = Logger("Handlers")
implicit val cs: ContextShift[IO] =
IO.contextShift(ExecutionContext.Implicits.global)
class DefaultHandler[A] {
val response: IO[MVar[IO, A]] = MVar.empty[IO, A]
def onResult(obj: Any): Unit = {
obj match {
case obj: A =>
println(response.flatMap(_.tryPut(obj)).unsafeRunSync())
println(response.flatMap(_.isEmpty).unsafeRunSync())
case _ => logger.error("Wrong expected type")
}
}
def getResponse: A = {
response.flatMap(_.take).unsafeRunSync()
}
}
但出于某种原因,tryPut 和 isEmpty(当我手动调用 onResult 方法时)returns 是的,因此当我调用 getResponse 时它会永远休眠。
这是我的测试:
class HandlersTest extends FunSuite {
test("DefaultHandler.test") {
val handler = new DefaultHandler[Int]
handler.onResult(3)
val response = handler.getResponse
assert(response != 0)
}
}
有人可以解释为什么 tryPut returns 为真,但没有任何内容。在 scala 中使用 Mvar/channels 的正确方法是什么?
IO[X]
表示您拥有创建一些 X 的方法。因此,在您的示例中,您输入一个 MVar 然后再输入一个
这是我的做法。
object Handlers {
trait DefaultHandler[A] {
def onResult(obj: Any): IO[Unit]
def getResponse: IO[A]
}
object DefaultHandler {
def apply[A : ClassTag]: IO[DefaultHandler[A]] =
MVar.empty[IO, A].map { response =>
new DefaultHandler[A] {
override def onResult(obj: Any): IO[Unit] = obj match {
case obj: A =>
for {
r1 <- response.tryPut(obj)
_ <- IO(println(r1))
r2 <- response.isEmpty
_ <- IO(println(r2))
} yield ()
case _ =>
IO(logger.error("Wrong expected type"))
}
override def getResponse: IO[A] =
response.take
}
}
}
}
"unsafe" 是一种暗示,但每次调用 unsafeRunSync
时,您基本上应该将其视为一个全新的宇宙。在你打电话之前,你只能描述将要发生的事情的说明,你不能真正改变任何事情。通话期间是所有更改发生的时间。调用完成后,该 universe 将被销毁,您可以读取结果但不再更改任何内容。一个 unsafeRunSync
宇宙中发生的事情不会影响另一个宇宙。
您需要在测试代码中只调用一次。这意味着您的测试代码需要类似于:
val test = for {
handler <- TestHandler.DefaultHandler[Int]
_ <- handler.onResult(3)
response <- handler.getResponse
} yield response
assert test.unsafeRunSync() == 3
请注意,与直接使用 MVar
相比,这并没有给您带来太多好处。我认为您正在尝试混合 IO
内部和外部的副作用,但这是行不通的。所有的副作用都需要在里面。
我写了简单的回调(处理程序)函数,我传递给异步 api 我想等待结果:
object Handlers {
val logger: Logger = Logger("Handlers")
implicit val cs: ContextShift[IO] =
IO.contextShift(ExecutionContext.Implicits.global)
class DefaultHandler[A] {
val response: IO[MVar[IO, A]] = MVar.empty[IO, A]
def onResult(obj: Any): Unit = {
obj match {
case obj: A =>
println(response.flatMap(_.tryPut(obj)).unsafeRunSync())
println(response.flatMap(_.isEmpty).unsafeRunSync())
case _ => logger.error("Wrong expected type")
}
}
def getResponse: A = {
response.flatMap(_.take).unsafeRunSync()
}
}
但出于某种原因,tryPut 和 isEmpty(当我手动调用 onResult 方法时)returns 是的,因此当我调用 getResponse 时它会永远休眠。 这是我的测试:
class HandlersTest extends FunSuite {
test("DefaultHandler.test") {
val handler = new DefaultHandler[Int]
handler.onResult(3)
val response = handler.getResponse
assert(response != 0)
}
}
有人可以解释为什么 tryPut returns 为真,但没有任何内容。在 scala 中使用 Mvar/channels 的正确方法是什么?
IO[X]
表示您拥有创建一些 X 的方法。因此,在您的示例中,您输入一个 MVar 然后再输入一个
这是我的做法。
object Handlers {
trait DefaultHandler[A] {
def onResult(obj: Any): IO[Unit]
def getResponse: IO[A]
}
object DefaultHandler {
def apply[A : ClassTag]: IO[DefaultHandler[A]] =
MVar.empty[IO, A].map { response =>
new DefaultHandler[A] {
override def onResult(obj: Any): IO[Unit] = obj match {
case obj: A =>
for {
r1 <- response.tryPut(obj)
_ <- IO(println(r1))
r2 <- response.isEmpty
_ <- IO(println(r2))
} yield ()
case _ =>
IO(logger.error("Wrong expected type"))
}
override def getResponse: IO[A] =
response.take
}
}
}
}
"unsafe" 是一种暗示,但每次调用 unsafeRunSync
时,您基本上应该将其视为一个全新的宇宙。在你打电话之前,你只能描述将要发生的事情的说明,你不能真正改变任何事情。通话期间是所有更改发生的时间。调用完成后,该 universe 将被销毁,您可以读取结果但不再更改任何内容。一个 unsafeRunSync
宇宙中发生的事情不会影响另一个宇宙。
您需要在测试代码中只调用一次。这意味着您的测试代码需要类似于:
val test = for {
handler <- TestHandler.DefaultHandler[Int]
_ <- handler.onResult(3)
response <- handler.getResponse
} yield response
assert test.unsafeRunSync() == 3
请注意,与直接使用 MVar
相比,这并没有给您带来太多好处。我认为您正在尝试混合 IO
内部和外部的副作用,但这是行不通的。所有的副作用都需要在里面。