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。为什么上面的第一组行不能正常工作,但也没有错误?
答案 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
提供)。