繁体   English   中英

在scala中使用def,val和var

[英]Use of def, val, and var in 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 person = new Person("Kumar",12) 如果我使用var或val,则输出为20 我理解scala中的默认值是val。 这个:

def age = 30
age = 45

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

在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)

我首先介绍了defvalvar之间Scala中存在的区别。

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

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

  • 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

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

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

为了提供另一个视角,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)

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

正如金太郎所说,人是一种方法(因为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

我们来看看:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM