有什么区别:
class Person(name: String, age: Int) {
def say = "My name is " + name + ", age " + age
}
和
class Person(val name: String, val age: Int) {
def say = "My name is " + name + ", age " + age
}
我可以声明参数var
S,后来又改变他们的价值观? 例如,
class Person(var name: String, var age: Int) {
age = happyBirthday(5)
def happyBirthday(n: Int) {
println("happy " + n + " birthday")
n
}
}
对于第一部分的答案是范围:
scala> class Person(name: String, age: Int) {
| def say = "My name is " + name + ", age " + age
| }
scala> val x = new Person("Hitman", 40)
scala> x.name
<console>:10: error: value name is not a member of Person
x.name
如果您使用前缀与参数val
, var
他们会从类之外可见,否则,他们将是私人的,你可以在上面代码中看到。
是的,你可以改变变种的价值,就像平常。
这个
class Person(val name: String, val age: Int)
使外部可用的类如以后可以做的用户领域
val p = new Person("Bob", 23)
val n = p.name
如果指定ARGS为var
,则作用域是一样的val
,但字段是可变的。
如果你熟悉Java,你可以从这个例子的想法:
class Person(name: String, age: Int)
类同
class Person {
public Person(String name, int age) {
}
}
而
class Person(var name: String, var age: Int) // also we can use 'val'
类似于
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
直觉是,如果没有VAR / VAL,变量只是在构造函数中进行访问。 如果添加的VAR / VAL,则类将具有相同名称的成员变量。
这里的答案是非常好的,但是我解决这个一个与探索字节码。 当您应用javap
一类,它打印出包,保护和公共领域,并通过了类的方法。 我创建了一个类Person.scala并用下面的代码填充它。
class Person(name: String, age: Int) {
def say = "My name is " + name + ", age " + age
}
class PersonVal(val name: String, val age: Int) {
def say = "My name is " + name + ", age " + age
}
class PersonVar(var name: String, var age: Int) {
age = happyBirthday(5)
def happyBirthday(n: Int) = {
println("happy " + n + " birthday")
n
}
}
编译的代码后scalac Person.scala
它生成三个文件与名称Person.class, PersonVal.calass , PersonVar.cass
。 通过运行javap
每个这些类文件,我们可以看到的结构会怎样:
>>javap Person.class
Compiled from "Person.scala"
public class Person {
public java.lang.String say();
public Person(java.lang.String, int);
}
在这种情况下,它并没有给任何人类varible因为它被声明既不VAL,也不VAL所以名字和年龄可以只是内部构造函数中使用。
>>javap PersonVal.class
public class PersonVal {
public java.lang.String name();
public int age();
public java.lang.String say();
public PersonVal(java.lang.String, int);
}
在这种情况下,它有三个成员两个用于输入构造函数和一个用来表示我们的constructore内声明的成员。 但是我们并没有为输入构造任意制定者,所以我们不能改变的值。
>>javap PersonVar.class
public class PersonVar {
public java.lang.String name();
public void name_$eq(java.lang.String);
public int age();
public void age_$eq(int);
public int happyBirthday(int);
public PersonVar(java.lang.String, int);
}
这是一样的PersonVal例子,但我们可以在这种情况下与那些改变数值variable_$eq
的方法。 它没有什么只是一个缩短的版本variable =
你可以使用一个case class
,并在这种情况下, Person
类将有可用的类之外的变量。 case class Person(name: String, age: Int)
。 然后按预期下面的代码会工作。 val z = new Person("John", 20); z.name //John
通过@Reza这里笔者探讨了利用javap的字节码的回答帮我澄清这个概念最好的。 举这种情况下的非常具体的例子请参考我在面对我的生产Web应用程序下面的情形(播放+斯卡拉): 如何注入参数到Scala中的一个类/特质方法
如果我不使用VAL前缀来注入参数authorizationHandler
那么编译器会引发这个错误:
class MyController needs to be abstract, since method authorizationHandler in trait AuthorizationCheck of type => controllers.authapi.AuthorizationHandler is not defined
[error] class MyController @Inject() (authorizationHandler: AuthorizationHandler) extends Controller with AuthorizationCheck {
[error] ^
[error] one error found
可悲的错误并没有帮我找出正确的问题,这与前缀val
。
class MyController @Inject()(val authorizationHandler: AuthorizationHandler) extends Controller with AuthorizationCheck {
def myAction = AuthenticatedAction { implicit request =>
...
}
}