【问题标题】:Implementing mutable methods in Scala classes在 Scala 类中实现可变方法
【发布时间】:2013-05-10 03:24:00
【问题描述】:

我是 Scala 新手。如何在类中实现方法?

我定义了一个特征,如下所示:

trait Node extends Component{
  val label:Int
  val inputEdges:List[Edge] = List[Edge]()
  val outputEdges:List[Edge] = List[Edge]()

  def addInputEdge(edge:Edge) = {
    inputEdges :+ edge
    this
  }

  def addOutputEdge(edge:Edge) = {
    outputEdges :+ edge
    this
  }
}

case class SomeNode(label:Int) extends Node

我需要帮助来了解如何实现这两种方法。

每个扩展 Node 的类都必须在构造函数中提供一个标签,但应该继承两个方法和两个列表。此外,这些方法应返回节点的新对象,并将边缘添加到列表之一。现在,如果我调用其中一种方法,我会得到相同的对象,但没有将边缘添加到列表之一。这是有道理的,但是当两个列表不可变时,我不知道如何添加边。

我真的不想在构造函数中传递列表,因为那样我会得到带有许多参数的构造函数。

【问题讨论】:

    标签: scala constructor functional-programming immutability


    【解决方案1】:

    我知道您要求的解决方案是列表不出现在构造函数中,但如果您使用默认参数,希望它是可以接受的。 (我很感兴趣为什么要避免“胖”构造函数、默认参数或伴随对象应用方法可以在这里提供帮助。)
    (顺便说一句:在特征中使用def 表示抽象事物,Seq 而不是List

    这是我的方法:

    trait Self[S] { self: S =>
      type SELF = S
    }
    
    trait Component
    trait Edge
    
    trait Node extends Component {
      type SELF
      protected def constructor: (Int, Seq[Edge], Seq[Edge]) => SELF
      def label: Int
      def inputEdges: Seq[Edge]
      def outputEdges: Seq[Edge]
      private def clone(inputEdges: Seq[Edge] = this.inputEdges, outputEdges: Seq[Edge] = this.outputEdges) = constructor(label, inputEdges, outputEdges)
      final def addInputEdge(edge: Edge) = clone(inputEdges = inputEdges :+ edge)
      final def addOutputEdge(edge: Edge) = clone(outputEdges = outputEdges :+ edge)
    }
    
    case class SomeNode(label: Int, inputEdges: Seq[Edge] = Seq(), outputEdges: Seq[Edge] = Seq()) extends Node with Self[SomeNode] {
      def constructor = SomeNode
    }
    
    val node1 = SomeNode(1)
    val node2: SomeNode = node1.addInputEdge(new Edge {})
    

    【讨论】:

    • 谢谢,但这似乎比拥有一个大的构造函数更令人困惑(至少对我来说)。我不喜欢大的构造函数,因为它们让我很难理解一个类在我看来到底是什么。我只是在为一种在 OOP 语言中是可变的方法寻找一种简单而优雅的解决方案。
    【解决方案2】:

    有几种方法可以完成您的要求。首先,您可以简单地将 inputEdges 和 outputEdges 定义为 vars 而不是 vals。这样,您可以将您在 addInputEdge 和 addOutputEdge 方法中创建的列表重新分配给相应的字段。

    trait Node extends Component {
      val label:Int
      var inputEdges:List[Edge] = List[Edge]()
      var outputEdges:List[Edge] = List[Edge]()
    
      def addInputEdge(edge:Edge) = {
        inputEdges = inputEdges :+ edge
        this
      }
    
      def addOutputEdge(edge:Edge) = {
        outputEdges = outputEdges :+ edge
        this
      }
    }
    

    然而,这引入了一个可能不受欢迎的可变状态。类似的替代方法是使用可变列表,例如MutableList。另一种方法是使添加方法抽象化,并让子类负责通过添加给定的边来创建它们自己的新实例。

    【讨论】:

      【解决方案3】:

      您可以只使用可变变量。不是很好... 重新考虑使用具有长构造函数的案例类。

      给你:

      trait Node extends Component{
        var label:Int
        var inputEdges:List[Edge] = List[Edge]()
        var outputEdges:List[Edge] = List[Edge]()
      
        def addInputEdge(edge:Edge) = {
          inputEdges :+= edge
          this
        }
      
        def addOutputEdge(edge:Edge) = {
          outputEdges:+=  edge
          this
        }
      }
      
      case class SomeNode(label:Int) extends Node
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-10-12
        • 2016-05-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-16
        相关资源
        最近更新 更多