在scala中使用def,val和var

Byj*_*edu 153 scala

class Person(val name:String,var age:Int )
def person = new Person("Kumar",12)
person.age = 20
println(person.age)
Run Code Online (Sandbox Code Playgroud)

这些代码行输出12,即使person.age=20已成功执行.我发现这是因为我使用了def def person = new Person("Kumar",12).如果我使用var或val,则输出为20.我理解scala中的默认值是val.这个:

def age = 30
age = 45
Run Code Online (Sandbox Code Playgroud)

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

Jes*_*per 245

在Scala中有三种定义方法:

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

看看你的代码:

def person = new Person("Kumar",12)
Run Code Online (Sandbox Code Playgroud)

这定义了一个名为的新方法person.您可以只调用此方法,()因为它被定义为无参数方法.对于empty-paren方法,您可以使用或不使用'()'来调用它.如果你只是写:

person
Run Code Online (Sandbox Code Playgroud)

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

person.age = 20
Run Code Online (Sandbox Code Playgroud)

会发生什么是你首先调用person方法,并在返回值(类的实例Person)上更改age成员变量.

最后一行:

println(person.age)
Run Code Online (Sandbox Code Playgroud)

在这里,您再次调用该person方法,该方法返回一个新的类实例Person(age设置为12).它与此相同:

println(person().age)
Run Code Online (Sandbox Code Playgroud)

  • 为了混淆事物,可以改变```val```的内部状态,但是val引用的对象不能.```val```不是常数. (23认同)
  • 为了进一步混淆事物,val(也可能是var,我还没试过)可以用来定义一个函数.当使用def来定义函数/方法时,每次调用def时都会对def的主体进行求值.使用val时,仅在定义时对其进行评估.请参阅http://stackoverflow.com/questions/18887264/what-is-the-difference-between-def-and-val-to-define-a-function (4认同)
  • 为了进一步混淆事物,def也可用于定义类的成员变量,不一定要使用var. (3认同)
  • @pferrel并不是真的让人困惑.与Java的最终版相同.您可以将`List`标记为`final`,但可以修改其内容. (2认同)

Pao*_*sca 95

我首先介绍了def,valvar之间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
Run Code Online (Sandbox Code Playgroud)

例如,val

scala> val somethingelse = 2 + 3 * 5 // it's evaluated, eagerly upon definition
somethingelse: Int = 17
Run Code Online (Sandbox Code Playgroud)

例子,var

scala> var aVariable = 2 * 3
aVariable: Int = 6

scala> aVariable = 5
aVariable: Int = 5
Run Code Online (Sandbox Code Playgroud)

根据上面的说法,defval的标签不能重新分配,如果有任何尝试,将引发如下所示的错误:

scala> something = 5 * 6
<console>:8: error: value something_= is not a member of object $iw
       something = 5 * 6
       ^
Run Code Online (Sandbox Code Playgroud)

当类被定义为:

scala> class Person(val name: String, var age: Int)
defined class Person
Run Code Online (Sandbox Code Playgroud)

然后实例化:

scala> def personA = new Person("Tim", 25)
personA: Person
Run Code Online (Sandbox Code Playgroud)

一个不可变的标签被用于人(即"人物角色)的该特定实例创建的.每当需要修改可变字段'age'时,此类尝试将失败:

scala> personA.age = 44
personA.age: Int = 25
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,'年龄'是不可变标签的一部分.处理此问题的正确方法包括使用可变变量,如下例所示:

scala> var personB = new Person("Matt", 36)
personB: Person = Person@59cd11fe

scala> personB.age = 44
personB.age: Int = 44    // value re-assigned, as expected
Run Code Online (Sandbox Code Playgroud)

很明显,从可变变量引用(即'personB')可以修改类可变字段'age'.

我仍然会强调,所有内容都来自上述差异,任何Scala程序员都必须清楚这一点.


Kin*_*aro 29

def person = new Person("Kumar", 12) 
Run Code Online (Sandbox Code Playgroud)

你正在定义一个函数/惰性变量,它总是返回一个名为"Kumar"且年龄为12的新Person实例.这是完全有效的,编译器没有理由抱怨.调用person.age将返回此新创建的Person实例的年龄,该实例始终为12.

写作时

person.age = 45
Run Code Online (Sandbox Code Playgroud)

您为类Person中的age属性分配一个新值,该值有效,因为age声明为var.如果您尝试person使用新的Person对象重新分配,编译器会抱怨

person = new Person("Steve", 13)  // Error
Run Code Online (Sandbox Code Playgroud)


xji*_*xji 25

为了提供另一个视角,Scala中的"def"表示每次使用都要评估的内容,而val是立即评估并且只评估一次的内容.在这里,表达式def person = new Person("Kumar",12)要求无论何时我们使用"人",我们都会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)
Run Code Online (Sandbox Code Playgroud)

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


Lan*_*dei 20

正如金太郎所说,人是一种方法(因为def)并且总是返回一个新的Person实例.如您发现,如果将方法更改为var或val,它将起作用:

val person = new Person("Kumar",12)
Run Code Online (Sandbox Code Playgroud)

另一种可能性是:

def person = new Person("Kumar",12)
val p = person
p.age=20
println(p.age)
Run Code Online (Sandbox Code Playgroud)

但是,person.age=20在您允许的代码中,当您Personperson方法中获取实例时,在此实例上,您可以更改a的值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
Run Code Online (Sandbox Code Playgroud)


Dan*_*ral 8

我们来看看:

class Person(val name:String,var age:Int )
def person =new Person("Kumar",12)
person.age=20
println(person.age)
Run Code Online (Sandbox Code Playgroud)

并用等效代码重写它

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)
Run Code Online (Sandbox Code Playgroud)

看,def是一种方法.它将在每次调用时执行,并且每次返回(a)new Person("Kumar", 12).并且这些在"赋值"中没有错误,因为它实际上不是赋值,而只是对age_=方法的调用(由提供var).