scala类构造函数参数
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了scala类构造函数参数相关的知识,希望对你有一定的参考价值。
有什么区别:
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
为参数添加前缀,那么它们将在课外显示,否则,它们将是私有的,如上面的代码所示。
是的,你可以改变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);
}
在这种情况下,它没有为Person创建任何类变量,因为它既没有val也没有val声明,因此name和age只能在构造函数中使用。
>>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中声明的成员。但是,我们没有输入构造函数的任何setter,因此我们无法更改值。
>>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
作者使用javap探索字节代码的@Reza的答案帮助我最好地阐明了这个概念。举一个这个案例的一个非常具体的例子,请参考我在生产网络应用程序(Play + Scala)中遇到的以下场景:How to inject parameters into a class/trait method in 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 =>
...
}
}
以上是关于scala类构造函数参数的主要内容,如果未能解决你的问题,请参考以下文章
scala入门教程:scala中的面向对象定义类,构造函数,继承
Scala 隐式类必须有一个主构造函数,在第一个参数列表中只有一个参数