在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中的def , val和var之间的区别开始。
-
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
根据上面的内容, 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')创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
提供)。