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 内部和外部的副作用,但这是行不通的。所有的副作用都需要在里面。