是否可以从同一Scala类的两个实例传递值

时间:2018-05-03 18:26:33

标签: scala class oop instance-variables

说我有这种情况

 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的变量输入有效加入两个管道但我无法弄清楚如果在同一个班级甚至可以做到这一点。所以我可以手动完成,但需要知道它是否可以在课堂上完成。

 pipe2.in = pipe1.out 

我尝试修复的方法是添加一个ID字段,然后尝试使用它来引用具有更高id字段的实例,但这看起来并不可行。即

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

    }

任何帮助将不胜感激

2 个答案:

答案 0 :(得分:0)

您可以通过为类定义一个伴随对象并将上游管道作为可选参数传递给factory方法,然后提取其值并将其传递给类构造函数来完成此操作,如下所示:

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))

答案 1 :(得分:0)

不幸的是,你的问题现在还不清楚。在某些假设下,您所描述的内容看起来像现在称为"FRP" aka "Functional Reactive Programming"。如果你想以一种认真的方式去做,你可能应该看看一些成熟的库,例如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)
}

打印

  

无   
in = 2.0   
一些(905.9999999999999)   
in = 3.0   
一些(909.0)   

在这里你的&#34;管道&#34;是RxCalculation1(或其他RxCalculationN)包装函数,你可以&#34;连接&#34;和&#34;断开&#34;其他&#34;管道&#34;或只是&#34;价值观&#34;各种输入并开始一系列更新。