在scala中使用def,val和var

时间:2010-12-14 08:52:49

标签: scala

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 个答案:

答案 0 :(得分:236)

在Scala中有三种定义方法:

  • def定义方法
  • val定义固定的(无法修改)
  • var定义变量(可以修改)

查看您的代码:

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)

答案 1 :(得分:90)

我首先要考虑Scala中 def val var 之间的区别。

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

  • val - 为右侧内容定义不可变标签急切/立即评估 - 按值评估。< / p>

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

示例,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

根据上述内容, def val 的标签无法重新分配,如果有任何尝试,将会引发如下错误:

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”)创建不可变标签。每当需要修改可变字段'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程序员都必须清楚这一点。

答案 2 :(得分:29)

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

答案 3 :(得分:25)

提供另一种观点,&#34; def&#34;在Scala中意味着每次在使用时被评估的东西,而val是立即评估的东西。在这里,表达式def person = new Person("Kumar",12)需要每当我​​们使用&#34; person&#34;我们会收到new Person("Kumar",12)电话。因此,这两个人的自然是很自然的。是无关的。

这是我理解Scala的方式(可能是更多&#34;功能&#34;方式)。我不确定是否

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

实际上是Scala的意思。我至少不想这么想......

答案 4 :(得分:19)

正如Kintaro所说,person是一种方法(因为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,并且在此实例中,您可以更改{的值{1}}。问题是,在该行之后您没有更多对该实例的引用(因为每次调用var都会产生一个新实例)。

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

person

答案 5 :(得分:8)

我们来看看:

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提供)。