0

说我有这种情况

 class Pipe {
    var vel = 3.4
    var V = 300
    var a = 10.2
    var in = ???
    var TotV = V+in
    var out = TotV*a/vel

    }

 val pipe1 = new Pipe
 val pipe2 = new Pipe

in 变量是我的问题,我想做的是从 pipe1 获取 out 变量并将其作为管道 2 的 in 变量有效地连接两个管道,但我不知道这是否可能在同一个班。所以我可以手动完成,但需要知道它是否可以在课堂上完成。

 pipe2.in = pipe1.out 

我尝试的解决方法是添加一个 ID 字段,然后尝试使用它来引用具有更高 id 字段的实例,但这似乎不可行。IE

class Pipe(id:Int) {
    var vel = 3.4
    var V = 300
    var a = 10.2
    var in = Pipe(id+1).out //this is the sticking point, I want to reference instances of this class and use their out value as in value for instances with a lower ID
    var TotV = V+in
    var out = TotV*a/vel

    }

任何帮助,将不胜感激

4

2 回答 2

0

您可以通过为该类定义一个伴随对象并将上游管道作为可选参数传递给工厂方法,然后提取其输入值并将其传递给类构造函数来做到这一点,如下所示:

object Pipe {
  def apply(upstreamPipe: Option[Pipe]): Pipe = {
    val inValue = upstreamPipe match {
      case Some(pipe) => pipe.out
      case None => 0 // or whatever your default value is
    new Pipe(inValue)
}

然后你会打电话

val pipe1 = Pipe(None)
val pipe2 = Pipe(Some(pipe1))
于 2018-05-04T15:01:24.203 回答
0

不幸的是,你的问题现在还不清楚。在某些假设下,您描述的内容看起来像现在所谓的“FRP”又名“功能反应式编程”。如果你想认真地做这件事,你可能应该看看一些成熟的库,比如RxScalaMonix,它们处理现实世界中许多重要的细节,比如错误处理或调度/线程等等。

对于一个简单的任务,您可能会推出一个简单的自定义实现,如下所示:

trait Observable {
  def subscribe(subscriber: Subscriber): RxConnection
}

trait RxConnection {
  def disconnect(): Unit
}

trait Subscriber {
  def onChanged(): Unit
}

trait RxOut[T] extends Observable {
  def currentValue: Option[T]
}

class MulticastObservable extends Observable with Subscriber {
  private val subscribers: mutable.Set[Subscriber] = mutable.HashSet()

  override def onChanged(): Unit = subscribers.foreach(s => s.onChanged())

  override def subscribe(subscriber: Subscriber): RxConnection = {
    subscribers.add(subscriber)
    new RxConnection {
      override def disconnect(): Unit = subscribers.remove(subscriber)
    }
  }
}


abstract class BaseRxOut[T](private var _lastValue: Option[T]) extends RxOut[T] {
  private val multicast = new MulticastObservable()

  protected def lastValue: Option[T] = _lastValue

  protected def lastValue_=(value: Option[T]): Unit = {
    _lastValue = value
    multicast.onChanged()
  }

  override def currentValue: Option[T] = lastValue

  override def subscribe(subscriber: Subscriber): RxConnection = multicast.subscribe(subscriber)
}

class RxValue[T](initValue: T) extends BaseRxOut[T](Some(initValue)) {
  def value: T = this.lastValue.get

  def value_=(value: T): Unit = {
    this.lastValue = Some(value)
  }
}

trait InputConnector[T] {
  def connectInput(input: RxOut[T]): RxConnection
}

class InputConnectorImpl[T] extends BaseRxOut[T](None) with InputConnector[T] {
  val inputHolder = new RxValue[Option[(RxOut[T], RxConnection)]](None)

  private def updateValue(): Unit = {
    lastValue = for {inputWithDisconnect <- inputHolder.value
                     value <- inputWithDisconnect._1.currentValue}
      yield value
  }

  override def connectInput(input: RxOut[T]): RxConnection = {
    val current = inputHolder.value
    if (current.exists(iwd => iwd._1 == input))
      current.get._2
    else {
      current.foreach(iwd => iwd._2.disconnect())
      inputHolder.value = Some(input, input.subscribe(() => this.updateValue()))
      updateValue()
      new RxConnection {
        override def disconnect(): Unit = {
          if (inputHolder.value.exists(iwd => iwd._1 == input)) {
            inputHolder.value.foreach(iwd => iwd._2.disconnect())
            inputHolder.value = None
            updateValue()
          }
        }
      }
    }
  }
}

abstract class BaseRxCalculation[Out] extends BaseRxOut[Out](None) {

  protected def registerConnectors(connectors: InputConnectorImpl[_]*): Unit = {
    connectors.foreach(c => c.subscribe(() => this.recalculate()))
  }

  private def recalculate(): Unit = {
    var newValue = calculateOutput()
    if (newValue != lastValue) {
      lastValue = newValue
    }
  }

  protected def calculateOutput(): Option[Out]
}

case class RxCalculation1[In1, Out](func: Function1[In1, Out]) extends BaseRxCalculation[Out] {
  private val conn1Impl = new InputConnectorImpl[In1]

  def conn1: InputConnector[In1] = conn1Impl // show to the outer world only InputConnector

  registerConnectors(conn1Impl)

  override protected def calculateOutput(): Option[Out] = {
    for {v1 <- conn1Impl.currentValue}
      yield func(v1)
  }
}

case class RxCalculation2[In1, In2, Out](func: Function2[In1, In2, Out]) extends BaseRxCalculation[Out] {
  private val conn1Impl = new InputConnectorImpl[In1]

  def conn1: InputConnector[In1] = conn1Impl // show to the outer world only InputConnector

  private val conn2Impl = new InputConnectorImpl[In2]

  def conn2: InputConnector[In2] = conn2Impl // show to the outer world only InputConnector

  registerConnectors(conn1Impl, conn2Impl)

  override protected def calculateOutput(): Option[Out] = {
    for {v1 <- conn1Impl.currentValue
         v2 <- conn2Impl.currentValue}
      yield func(v1, v2)
  }
}

// add more RxCalculationN if needed

你可以像这样使用它:

def test(): Unit = {

  val pipe2 = new RxCalculation1((in: Double) => {
    println(s"in = $in")
    val vel = 3.4
    val V = 300
    val a = 10.2
    val TotV = V + in
    TotV * a / vel
  })

  val in1 = new RxValue(2.0)
  println(pipe2.currentValue)
  val conn1 = pipe2.conn1.connectInput(in1)
  println(pipe2.currentValue)
  in1.value = 3.0
  println(pipe2.currentValue)
  conn1.disconnect()
  println(pipe2.currentValue)
}

哪个打印


在 = 2.0
一些(905.9999999999999)
在 = 3.0
一些(909.0)

在这里,您的“管道”是RxCalculation1(或其他RxCalculationN)包装了一个函数,您可以“连接”和“断开”其他“管道”或只是“值”到各种输入并启动一系列更新。

于 2018-05-04T18:13:27.950 回答