在scala中使用def,val和var

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 。 我明白默认是在斯卡拉val。 这个:

 def age = 30 age = 45 

…给出编译错误,因为它默认是一个val。 为什么上面的第一行不能正常工作,而且也不会出错?

在Scala中定义事物有三种方法:

  • def定义了一个方法
  • val定义了一个固定 (不能修改)
  • var定义了一个variables (可以修改)

看你的代码:

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

这定义了一个叫做person的新方法。 您可以仅在没有()情况下调用此方法,因为它被定义为无参数方法。 对于空白方法,可以使用或不使用“()”来调用它。 如果你只是写:

 person 

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

 person.age = 20 

发生什么事是你首先调用person方法,并且在返回值( Person类的一个实例)上,你正在改变age成员variables。

最后一行:

 println(person.age) 

在这里,您再次调用person方法,该方法返回Person类的新实例( age设置为12)。 这是一样的:

 println(person().age) 

我会从Scala中的defvalvar之间的区别开始。

  • def – 为延迟评估的右侧内容定义一个不可变的标签 – 按名称评估。

  • val – 为热切/立即评估的右侧内容定义一个不可变的标签 – 按值进行评估。

  • var – 定义一个可变variables ,最初设置为评估的右侧内容。

例如,def

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

例如,val

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

例如,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的特定实例(即'personA')创build一个不可变的标签 。 每当可变字段“年龄”需要修改时,这样的尝试失败:

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

如预期的那样,“年龄”是不可变的标签的一部分。 处理这个问题的正确方法是使用一个可变variables,如下例所示:

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

可变variables引用 (即“personB”)中可以清楚地看出,可以修改类可变字段“age”。

我仍然会强调一切都来自于上述差异,这一点在任何Scala程序员的脑海中都必须清楚。

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

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

写作时

 person.age = 45 

您将为Person类中的age属性指定一个新的值,因为age被声明为var ,所以这个值是有效的。 编译器会抱怨,如果你试图重新分配一个人像一个新的Person对象

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

为了提供另一个angular度,Scala中的“def”意味着每次使用它时会被评估的东西,而val是被立即评估并且只评估一次的东西 。 在这里, def person = new Person("Kumar",12)这个expression意味着每当我们使用“person”时,我们会得到一个new Person("Kumar",12) 。 所以这两个“人物”是不相关的。

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

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

实际上是Scala打算的意思。 我至less不喜欢这样想。

正如Kintaro所说,人是一种方法(因为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.age=20是允许的,因为你从person方法中取回一个Person实例,在这个实例中,你可以改变一个var的值。 问题是,在那一行之后,你没有更多的参考该实例(因为每个人的电话会产生一个新的实例)。

这没有什么特别的,你会在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 

我们来看看这个:

 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) 。 而这些在“赋值”中没有错误,因为它不是一个真正的赋值,而只是调用了age_=方法(由var提供)。