首页 文章

在scala中使用def,val和var

提问于
浏览
142
class Person(val name:String,var age:Int )
def person = new Person("Kumar",12)
person.age = 20
println(person.age)

这些代码行输出 12 ,即使 person.age=20 已成功执行 . 我发现这是因为我在 def person = new Person("Kumar",12) 中使用了def . 如果我使用var或val,则输出为 20 . 我理解scala中的默认值是val . 这个:

def age = 30
age = 45

...给出编译错误,因为它默认为val . 为什么上面的第一组行不能正常工作,而且还没有错误?

6 回答

  • 24

    在Scala中有三种定义方法:

    • def 定义 method

    • val 定义了一个固定的 value (不能修改)

    • var 定义 variable (可以修改)

    看看你的代码:

    def person = new Person("Kumar",12)
    

    这定义了一个名为 person 的新方法 . 您只能在没有 () 的情况下调用此方法,因为它被定义为无参数方法 . 对于empty-paren方法,您可以使用或不使用'()'来调用它 . 如果你只是写:

    person
    

    那么你正在调用这个方法(如果你没有分配返回值,它将被丢弃) . 在这行代码中:

    person.age = 20
    

    会发生什么是您首先调用 person 方法,并在返回值(类 Person 的实例)上更改 age 成员变量 .

    最后一行:

    println(person.age)
    

    在这里,您再次调用 person 方法,该方法返回类 Person 的新实例( age 设置为12) . 它与此相同:

    println(person().age)
    
  • 83

    我将从 defvalvar 之间的Scala中存在的区别开始 .

    • def - 为右侧内容定义不可变标签 lazily evaluated - 按名称评估 .

    • val - 为右侧内容定义不可变标签_11101515_ - 按值评估 .

    • var - 定义一个可变变量,最初设置为评估的右侧内容 .

    Example, def

    scala> def something = 2 + 3 * 4 
    something: Int
    scala> something  // now it's evaluated, lazily upon usage
    res30: Int = 14
    

    Example, val

    scala> val somethingelse = 2 + 3 * 5 // it's evaluated, eagerly upon definition
    somethingelse: Int = 17
    

    Example, var

    scala> var aVariable = 2 * 3
    aVariable: Int = 6
    
    scala> aVariable = 5
    aVariable: Int = 5
    

    根据以上所述, defval 中的标签无法重新分配,如果有任何尝试,将引发如下所示的错误:

    scala> something = 5 * 6
    <console>:8: error: value something_= is not a member of object $iw
           something = 5 * 6
           ^
    

    当类被定义为:

    scala> class Person(val name: String, var age: Int)
    defined class Person
    

    然后实例化:

    scala> def personA = new Person("Tim", 25)
    personA: Person
    

    为该特定Person实例创建 immutable label (即'personA') . 每当需要修改可变字段'age'时,此类尝试将失败:

    scala> personA.age = 44
    personA.age: Int = 25
    

    正如预期的那样,'年龄'是不可变标签的一部分 . 处理此问题的正确方法包括使用可变变量,如下例所示:

    scala> var personB = new Person("Matt", 36)
    personB: Person = Person@59cd11fe
    
    scala> personB.age = 44
    personB.age: Int = 44    // value re-assigned, as expected
    

    同样清楚,从可变变量引用(即'personB')可以修改类可变字段'age' .

    我仍然会强调,所有内容都来自上述差异,任何Scala程序员都必须清楚这一点 .

  • 19

    def person = new Person("Kumar", 12)
    

    你正在定义一个函数/惰性变量,它总是返回一个名为“Kumar”且年龄为12的新Person实例 . 这是完全有效的,编译器没有理由抱怨 . 调用person.age将返回此新创建的Person实例的年龄,该实例始终为12 .

    写作时

    person.age = 45
    

    您为类Person中的age属性分配一个新值,该值有效,因为age被声明为 var . 如果您尝试使用新的Person对象重新分配 person ,编译器会抱怨

    person = new Person("Steve", 13)  // Error
    
  • 29

    为了提供另一个视角,Scala中的"def"表示每次使用时都要评估的内容,而val是立即评估的内容 . 这里,表达式 def person = new Person("Kumar",12) 需要每当我们使用"person"时,我们将得到一个 new Person("Kumar",12) 调用 . 因此,两个"person.age"是无关的,这是很自然的 .

    这是我理解Scala的方式(可能是以更“功能”的方式) . 我不确定

    def defines a method
    val defines a fixed value (which cannot be modified)
    var defines a variable (which can be modified)
    

    实际上是斯卡拉的意思 . 我真的不喜欢这样思考至少......

  • 8

    正如金太郎所说,人是一种方法(因为def)并且总是返回一个新的Person实例 . 如您发现,如果将方法更改为var或val,它将起作用:

    val person = new Person("Kumar",12)
    

    另一种可能性是:

    def person = new Person("Kumar",12)
    val p = person
    p.age=20
    println(p.age)
    

    但是,当您从 person 方法返回 Person 实例时,允许在您的代码中使用 person.age=20 ,并且在此实例中,您可以更改 var 的值 . 问题是,在那一行之后你没有更多的引用那个实例(就像每一个调用 person 将生成一个新实例) .

    这没什么特别的,你在Java中会有完全相同的行为:

    class Person{ 
       public int age; 
       private String name;
       public Person(String name; int age) {
          this.name = name;  
          this.age = age;
       }
       public String name(){ return name; }
    }
    
    public Person person() { 
      return new Person("Kumar", 12); 
    }
    
    person().age = 20;
    System.out.println(person().age); //--> 12
    
  • 232

    我们来看看:

    class Person(val name:String,var age:Int )
    def person =new Person("Kumar",12)
    person.age=20
    println(person.age)
    

    并用等效代码重写它

    class Person(val name:String,var age:Int )
    def person =new Person("Kumar",12)
    (new Person("Kumar", 12)).age_=(20)
    println((new Person("Kumar", 12)).age)
    

    请参阅 def 是一种方法 . 它将在每次调用时执行,并且每次它将返回(a) new Person("Kumar", 12) . 这些在"assignment"中没有错误,因为它实际上不是一个赋值,而只是调用 age_= 方法(由 var 提供) .

相关问题