Scala class members and constructor parameters name clash

前端 未结 4 1733
北荒
北荒 2021-02-05 07:30

Consider the following class written in Java:

class NonNegativeDouble {
    private final double value;
    public NonNegativeDouble(double value) {
        this         


        
相关标签:
4条回答
  • 2021-02-05 07:55

    @Daniel C. Sobral

    class NonNegativeDouble(initValue: Double) {
      val value = Math.abs(initValue)
    }
    

    your code is right, but "constructor parameters are properties",this is not true.

    A post from the official site said,

    A parameter such as class Foo(x : Int) is turned into a field if it is referenced in one or more methods

    And Martin's reply confirms its truth:

    That's all true, but it should be treated as an implementation technique. That's why the spec is silent about it.

    So normally, we can still treat primary constructor parameters as normal method parameter, but when the parameters is referenced by any of the methods, the compiler will cleverly turn it into a private field.

    If any formal parameter preceded by the val, the compiler generates an getter definition automatically.if var, generates a setter additionally. see the language speification section 5.3.

    That's all about primary constructor parameters.

    0 讨论(0)
  • 2021-02-05 07:55

    In the case of case classes it should be:

    case class NonNegativeDouble(private val initValue: Double) {
      val value = Math.abs(initValue)
      def copy(value: Double = this.value) = NonNegativeDouble(value)
    }
    

    The implementation of copy is required to prevent the sintesized version of the compiler that will bind the initValue argument.

    I expect that the compiler is smart enough to not retain the «extra space» for the initValue. I haven't verified this behaviour.

    0 讨论(0)
  • 2021-02-05 08:01

    You can consider parametric field

    class NonNegativeDouble(val value: Double, private val name: String ){
      if (value < 0) throw new IllegalArgumentException("value cannot be negative")
      override def toString = 
        "NonNegativeDouble(value = %s, name = %s)" format (value, name)
    }
    
    val tom = "Tom"
    val k = -2.3
    
    val a = new NonNegativeDouble(k.abs, tom)
    a: NonNegativeDouble = NonNegativeDouble(value = 2.3, name = Tom)
    
    a.value
    res13: Double = 2.3
    
    a.name
    <console>:12: error: value name in class NonNegativeDouble cannot be accessed in NonNegativeDouble
         a.name
    
    val b = new NonNegativeDouble(k, tom)
    java.lang.IllegalArgumentException: value cannot be negative
    ...
    

    It's defines fields and parameters with the same names "value", "name". You can add modifiers such as private ...

    0 讨论(0)
  • 2021-02-05 08:05

    No, you can't. In Scala, constructor parameters are properties, so it makes no sense to redefine them.

    The solution, naturally, is to use another name:

    class NonNegativeDouble(initValue: Double) {
      val value = Math.abs(initValue)
    }
    

    Used like this, initValue won't be part of the instances created. However, if you use it in a def or a pattern matching declaration, then it becomes a part of every instance of the class.

    0 讨论(0)
提交回复
热议问题