scala 类构造函数参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15639078/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
scala class constructor parameters
提问by zihaoyu
What's the difference between:
有什么区别:
class Person(name: String, age: Int) {
def say = "My name is " + name + ", age " + age
}
and
和
class Person(val name: String, val age: Int) {
def say = "My name is " + name + ", age " + age
}
Can I declare parameters as vars, and change their values later? For instance,
我可以将参数声明为vars,然后再更改它们的值吗?例如,
class Person(var name: String, var age: Int) {
age = happyBirthday(5)
def happyBirthday(n: Int) {
println("happy " + n + " birthday")
n
}
}
回答by om-nom-nom
For the first part the answer is scope:
第一部分的答案是范围:
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
If you prefix parameters with val, varthey will be visible from outside of class, otherwise, they will be private, as you can see in code above.
如果使用 前缀参数val,var它们将从类外部可见,否则它们将是私有的,如您在上面的代码中所见。
And yes, you can change value of the var, just like usually.
是的,您可以像往常一样更改 var 的值。
回答by Brian Agnew
This
这
class Person(val name: String, val age: Int)
makes the fields available externally to users of the class e.g. you can later do
使该类的用户可以外部使用这些字段,例如您以后可以这样做
val p = new Person("Bob", 23)
val n = p.name
If you specify the args as var, then the scoping is the same as for val, but the fields are mutable.
如果您将 args 指定为var,则范围与 for 相同val,但字段是可变的。
回答by yxjiang
If you are familiar with Java, you can get the idea from this example:
如果你熟悉 Java,你可以从这个例子中得到想法:
class Person(name: String, age: Int)
is similiar to
类似于
class Person {
public Person(String name, int age) {
}
}
While
尽管
class Person(var name: String, var age: Int) // also we can use 'val'
is similar to
类似于
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
The intuition is that without var/val, the variable is only accessible inside the constructor. If var/val is added, the class will have the member variables with the same name.
直觉是,如果没有 var/val,变量只能在构造函数内部访问。如果添加了 var/val,则该类将具有同名的成员变量。
回答by Reza
The answers here are really good, however I'm tackling this one with exploring the byte code. When you apply javapon a class, it prints out package, protected, and public fields and methods of the classes passed. I created a class Person.scala and filled it out with the following code.
这里的答案非常好,但是我正在通过探索字节码来解决这个问题。当您申请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
}
}
After compiling the code with scalac Person.scalait generates three files with names Person.class, PersonVal.calass , PersonVar.cass. By running javapfor each of these class files we can see how the structure would be:
用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);
}
In this case it didn't create any class varible for Person since it is declared with neither val, nor val so name and age can just be used inside constructor.
在这种情况下,它没有为 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);
}
In this case it has three members two for the input constructor and one for the member that we declared inside the constructore. However we don't have any setter for the input constructors so we can't change the values.
在这种情况下,它有三个成员,两个用于输入构造函数,一个用于我们在构造函数中声明的成员。但是,我们没有用于输入构造函数的任何 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);
}
It's the same as PersonVal example but we can change the values in this case with those variable_$eqmethods. it nothing just a shortened version of variable =
它与 PersonVal 示例相同,但在这种情况下我们可以使用这些variable_$eq方法更改值。它只是一个缩短的版本variable =
回答by NKM
The answer by @Reza where the author explores byte code using javap helped me to clarify this concept the best. To cite a very specific example of this case please refer to below scenario that I faced in my production web app (Play + Scala): How to inject parameters into a class/trait method in Scala
@Reza 作者使用 javap 探索字节码的答案帮助我最好地阐明了这个概念。要引用这个案例的一个非常具体的例子,请参考我在我的生产网络应用程序(Play + Scala)中遇到的以下场景: 如何将参数注入 Scala 中的类/特征方法
If I don't use val prefix to injected parameter authorizationHandlerthen
compiler throws this error:
如果我不使用 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
Sadly the error didn't help me to pinpoint to the correct issue which is to prefix with val.
可悲的是,该错误并没有帮助我确定正确的问题,即以val.
class MyController @Inject()(val authorizationHandler: AuthorizationHandler) extends Controller with AuthorizationCheck {
def myAction = AuthenticatedAction { implicit request =>
...
}
}
回答by TheM00s3
You could use a case classand in that case the Personclass would have those variables available outside of the class.
case class Person(name: String, age: Int). Then the following code would work as expected. val z = new Person("John", 20); z.name //John
您可以使用 a case class,在这种情况下,Person该类将在类之外使用这些变量。
case class Person(name: String, age: Int). 然后下面的代码将按预期工作。val z = new Person("John", 20); z.name //John

