0

私はrxscalaを使用していて、非常に微妙な問題を発見しました.私のコードは次のように単純化されています:

import rx.lang.scala.Observable
import rx.lang.scala.subjects.PublishSubject

object SubtleBug extends App {

  case class Projects(projects: List[Project] = Nil)
  case class Project(name: String, docs: List[Doc] = Nil)
  case class Doc(path: String, baseContent: String)

  sealed trait ServerEvent
  case class ProjectNames(projects: Seq[String]) extends ServerEvent
  case class NewDocument(projectName: String, path: String, version: Int, content: String) extends ServerEvent

  val receivedEvents = PublishSubject[ServerEvent]

  new Thread(new Runnable {
    override def run(): Unit = {
      val events = Seq(
        new ProjectNames(Seq("p1", "p2")),
        NewDocument("p1", "/aaa", 1, "my-content"),
        NewDocument("p1", "/bbb", 1, "my-content")
      )
      events.foreach { event =>
        receivedEvents.onNext(event)
        Thread.sleep(200)
      }
    }
  }).start()

  lazy val projects: Observable[Option[Projects]] = receivedEvents.scan(Option.empty[Projects]) {
    case (_, ProjectNames(names)) => {
      Some(Projects(names.map(name => Project(name)).toList))
    }
    case (Some(ps), NewDocument(projectName, docPath, version, content)) => {
      val doc = Doc(docPath, content)
      val newPs = ps.copy(projects = ps.projects.map {
        case project if project.name == projectName => project.copy(docs = project.docs ::: List(doc))
        case p => p
      })
      Some(newPs)
    }
    case _ => None
  }.collect({
    case Some(p) => Some(p)
  })

  projects.foreach(ps => {
    println("### 111: " + ps.map(_.projects))
    projects.foreach(x => println("### 222: " + ps.map(_.projects))) // !!!(2)
  })

  Thread.sleep(2000)

}

キーポイントは、それ自体!!!(2)の内側にある線です。projects

以下を出力します。

### 111: Some(List(Project(p1,List()), Project(p2,List())))
### 111: Some(List(Project(p1,List(Doc(/aaa,my-content))), Project(p2,List())))
### 111: Some(List(Project(p1,List(Doc(/aaa,my-content), Doc(/bbb,my-content))), Project(p2,List())))

線がないのが難点### 222:

しかし、collectパーツを変更してケースを追加するとNone:

.collect({
  case Some(p) => Some(p)
  case None => None // added case
})

### 222:期待どおりに行が出力されます。

### 111: None
### 111: Some(List(Project(p1,List()), Project(p2,List())))
### 111: Some(List(Project(p1,List(Doc(/aaa,my-content))), Project(p2,List())))
### 222: None
### 222: None
### 222: Some(List(Project(p1,List()), Project(p2,List())))
### 222: Some(List(Project(p1,List()), Project(p2,List())))
### 111: Some(List(Project(p1,List(Doc(/aaa,my-content), Doc(/bbb,my-content))), Project(p2,List())))
### 222: None
### 222: Some(List(Project(p1,List()), Project(p2,List())))
### 222: Some(List(Project(p1,List(Doc(/aaa,my-content))), Project(p2,List())))
### 222: Some(List(Project(p1,List(Doc(/aaa,my-content))), Project(p2,List())))

理由がわかりません。

PS: ここでコードを複製できます: https://github.com/freewind/rxscala-test/blob/master/src/main/scala/myrx/SubtleBug.scala

4

1 に答える 1

0

コードに競合状態があります。PublishSubjectサブスクライブする前に、すべてのイベントをドロップします。そのため、 のreceivedEvents.onNext(event)前に実行するprojects.foreachと、イベントはドロップされます。ではscan、最初のイベントがドロップされると、パターン マッチは機能しなくなります。

を使用ReplaySubjectして修正できます。

于 2015-11-20T19:04:30.527 に答える