Initializing a val lately

前端 未结 3 1558
旧时难觅i
旧时难觅i 2021-01-23 17:51

Is it possible to do that in Scala using only val:

class MyClass {
  private val myVal1: MyClass2 //.....????? what should be here?

  def myMethod1(param1: Int)         


        
3条回答
  •  不知归路
    2021-01-23 18:49

    This is not possible, but there are some ways (in addition to using param1 as a constructor parameter)

    1. Change the var into an Option; the setter myMethod1 returns a new instance of the same class with the Option set to the value.
    2. Create a separate mutable Builder class with a var, and turn it into an immutable one later, when all data has been collected
    3. If you are dealing with forward or cyclic references, consider using call-by-name and lazy vals (example 1, example 2)

    Update: Example for 1:

    class MyClass(val myVal1: Option[Int]) {
      def myMethod1(param1: Int): MyClass = {
        new MyClass(Some(param1))
      }
    }
    
    object MyClass {
      def apply() = new MyClass(None)
      def apply(i: Int) = new MyClass(Some(i))
    }
    

    This pattern is used by immutable.Queue for example.


    Update: Example for 3 (cyclic reference):

    // ref ... call by name
    class MyClass(val id: Int, ref: => MyClass) {
      lazy val myVal1 = ref
    
      override def toString: String = s"$id -> ${myVal1.id}"
    }
    

    to be used like this:

    val a: MyClass = new MyClass(1, b)
    val b: MyClass = new MyClass(2, a)
    println(a)
    println(b)
    

    Update: Example for 3 (forward reference):

    class MyClass2(val id: Int)
    
    // ref ... call by name
    class MyClass(val id: Int, ref: => MyClass2) {
      lazy val myVal1 = ref
    
      override def toString: String = s"$id -> ${myVal1.id}"
    }
    

    to be used with

    val a = new MyClass(1, x)
    println(a.id) // You can use a.id, but not yet the lazy val
    val x = new MyClass2(10)
    println(a)
    

提交回复
热议问题