【问题标题】:Scala: How to set an instance field defined in an abstract super class constructor?Scala:如何设置在抽象超类构造函数中定义的实例字段?
【发布时间】:2012-10-18 12:04:28
【问题描述】:

给定两个类:

 abstract class ClassA(val argA:Int = 1) {
   def func1 {
     ... argA ... //some operations
     func2
   }
   def func2
 }

class ClassB extends ClassA {
   def func2 {
     ... argA ... //some operations
   }
}

val b = new ClassB
b.func1

如何在实例化 b 时传递 argA=3? 像B这样的子类会有几十个,不用重写就好了 每个类定义中都有“(val argA:Int = 1)”。即使在这种情况下,事情也会变得模糊不清。

我发现的最相似的问题是关于获取而不是设置值: question

【问题讨论】:

    标签: scala inheritance parameters constructor arguments


    【解决方案1】:

    只需将参数传递给 ClassA:

    class ClassB extends ClassA(3) { ... }
    

    【讨论】:

    • “如何在 实例化 b 时传递 argA=3”,而不是扩展。默认值应保持为 1。
    • val b = new ClassB 将在实例化 b 时传递 argA=3。根据您的问题,ClassB 不接受 args。如果你想这样,你必须写class ClassB(argA: Int = 1) extends ClassA(argA)。如果您有一大堆默认参数,您可能希望将它们抽象为一个案例类,您可以在该类上使用copy 更改值。
    【解决方案2】:

    在实例化时覆盖 argA

    val b = new ClassB {
        override val argA = 3
    }
    

    根据您写的内容,这似乎是做您想做的最简洁的方式。不过,根据您的实际使用情况,您可能会通过在伴随对象上定义一些方法来找到一些不太笨重的方法来实例化您的对象。

    【讨论】:

      【解决方案3】:
      abstract class ClassA {
          val argA: Int = 1
          def func1() {
              println(argA)
          }
      }
      
      class ClassB extends ClassA {
          def func2() {
              println("B: %d" format argA)
          }
      }
      
      val b = new ClassB { override val argA = 3 }
      b.func1()
      

      【讨论】:

        【解决方案4】:

        只需在类定义中传递它:

        class ClassB( i: Int ) extends ClassA(i) { ... }
        
        val cb = new ClassB( 3 )
        

        【讨论】:

          【解决方案5】:

          如您所见,有几种可能的方法可以实现您的要求。然而,哪一个是最好的方式并不明显,因为这取决于您想要强调的内容(简洁性、重用性、性能)以及实际代码的外观。一些值得记住的事情是:


          通过@maackle 的解决方案,表单的每个实例化

          val b = new ClassB { override val argA = 3 }
          

          将产生一个在幕后创建的匿名类class AnonSubB extends ClassB。如果您想专注于简洁,那么这可能是要走的路,但是如果匿名类的数量增加,它们可能会减慢编译速度。


          @paradigmatic 的解决方案

          class ClassB(i: Int) extends ClassA(i) { ... }
          val cb = new ClassB(3)
          

          几乎一样简洁并且不会产生匿名类,但缺点是ClassA 指定的argA 的默认值没有被重用(它在@maackle 的解决方案中)。您可以重复该值,即将ClassB 声明为

          class ClassB(i: Int = 1) extends ClassA(i) { ... }
          

          但这很容易出错,因为如果需要更改,您必须在各个地方更改默认值。


          我还想提供一个我自己的解决方案,重点在于重用默认值而不创建匿名类,但这不太简洁:

          /* ClassA has a reusable (referenceable) default value */
          abstract class ClassA(val argA: Int) {
            def this() = this(ClassA.defaultArgA)
          }
          
          object ClassA {
            val defaultArgA = 1
          }
          
          /* ClassB reuses ClassA's default value */
          class ClassB(x: Int = ClassA.defaultArgA) extends ClassA(x)
          
          /* ClassC has a local (non-referenceable) default value */
          class ClassC(x: Int = 10) extends ClassA(x)
          
          println(new ClassB(2).argA) // 2
          println(new ClassB().argA)  // 1
          println(new ClassC().argA)  // 10
          

          【讨论】:

            猜你喜欢
            • 2017-12-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-04-28
            • 2015-06-03
            相关资源
            最近更新 更多