斯卡拉类的构造函数参数(scala class constructor parameters)

2019-07-23 12:57发布

有什么区别:

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
  }
}

Answer 1:

对于第一部分的答案是范围:

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

如果您使用前缀与参数valvar他们会从类之外可见,否则,他们将是私人的,你可以在上面代码中看到。

是的,你可以改变变种的价值,就像平常。



Answer 2:

这个

class Person(val name: String, val age: Int)

使外部可用的类如以后可以做的用户领域

val p = new Person("Bob", 23)
val n = p.name

如果指定ARGS为var ,则作用域是一样的val ,但字段是可变的。



Answer 3:

如果你熟悉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,则类将具有相同名称的成员变量。



Answer 4:

这里的答案是非常好的,但是我解决这个一个与探索字节码。 当您应用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 =



Answer 5:

你可以使用一个case class ,并在这种情况下, Person类将有可用的类之外的变量。 case class Person(name: String, age: Int) 。 然后按预期下面的代码会工作。 val z = new Person("John", 20); z.name //John



Answer 6:

通过@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 =>
     ...
   }
} 


文章来源: scala class constructor parameters