parametry konstruktora klasy scala

Jaka jest różnica między:

class Person(name: String, age: Int) {
  def say = "My name is " + name + ", age " + age
}

I

class Person(val name: String, val age: Int) { 
  def say = "My name is " + name + ", age " + age
}

Czy mogę zadeklarować parametry jako var s, a później zmienić ich wartości? Na przykład,

class Person(var name: String, var age: Int) {

  age = happyBirthday(5)

  def happyBirthday(n: Int) {
    println("happy " + n + " birthday")
    n
  }
}
Author: zihaoyu, 2013-03-26

6 answers

W pierwszej części odpowiedź brzmi:

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

Jeśli prefiks parametrów z val, var będą widoczne spoza klasy, w przeciwnym razie będą prywatne, jak widać w kodzie powyżej.

I tak, możesz zmienić wartość var, tak jak zwykle.

 41
Author: om-nom-nom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-26 14:08:58

To

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

Udostępnia pola zewnętrznie użytkownikom klasy, np. można później zrobić

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

Jeśli podasz args jako var, to zakres jest taki sam jak dla val, ale pola są zmienne.

 10
Author: Brian Agnew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-26 14:08:32

Jeśli znasz Javę, możesz uzyskać pomysł z tego przykładu:

class Person(name: String, age: Int)

Jest podobny do

class Person {
  public Person(String name, int age) {
  }
}

While

class Person(var name: String, var age: Int) // also we can use 'val'

Jest podobny do

class Person {
  String name;
  int age;

  public Person(String name, int age) {
     this.name = name;
     this.age = age;
  }
}

Intuicja jest taka, że bez var/val zmienna jest dostępna tylko wewnątrz konstruktora. Jeśli zostanie dodany var/val, klasa będzie miała zmienne członkowskie o tej samej nazwie.

 8
Author: yxjiang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-23 22:39:33

Odpowiedzi tutaj są naprawdę dobre, jednak zajmuję się tym, badając kod bajtowy. Gdy zastosujesz javap do klasy, wyświetla ona pola package, protected i public oraz metody przekazywanych klas. Stworzyłem osobę z klasą.scala i wypełnił go poniższym kodem.

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

Po skompilowaniu kodu z scalac Person.scala generuje on trzy pliki o nazwach Person.class, PersonVal.calass , PersonVar.cass. Uruchamiając javap dla każdego z tych plików klas możemy zobaczyć jak struktura be:

>>javap Person.class
Compiled from "Person.scala"
public class Person {
  public java.lang.String say();
  public Person(java.lang.String, int);
}

W tym przypadku nie tworzy żadnej klasy variable for Person, ponieważ nie jest zadeklarowana ani przez val, ani przez val, więc nazwa i wiek mogą być użyte wewnątrz konstruktora.

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

W tym przypadku ma on trzy elementy: dwa dla konstruktora wejściowego i jeden dla elementu zadeklarowanego wewnątrz constructore. Jednak nie mamy żadnego settera dla konstruktorów wejściowych, więc nie możemy zmienić wartości.

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

To to samo co przykład PersonVal, ale możemy zmienić wartości w tym przypadku za pomocą metod variable_$eq. to nic tylko skrócona wersja variable =

 2
Author: Reza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-16 15:54:20

Możesz użyć case class i w takim przypadku klasa Person będzie miała te zmienne dostępne poza klasą. case class Person(name: String, age: Int). Następnie poniższy kod będzie działał zgodnie z oczekiwaniami. val z = new Person("John", 20); z.name //John

 1
Author: TheM00s3,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-12 19:02:07

Odpowiedź @Reza, gdzie autor bada kod bajtowy za pomocą javap, pomogła mi wyjaśnić tę koncepcję najlepiej. Aby przytoczyć bardzo konkretny przykład tego przypadku, zapoznaj się z poniższym scenariuszem, który napotkałem w mojej aplikacji internetowej produkcji (Play + Scala): Jak wprowadzić parametry do metody class / trait w Scali

If I don ' t use val prefix to injected parameter authorizationHandler then kompilator wyrzuca ten błąd:

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

Niestety błąd nie pomógł mi wskazać poprawnego problem, który należy przedrostkiem val.

class MyController @Inject()(val authorizationHandler: AuthorizationHandler) extends Controller with AuthorizationCheck {

   def myAction = AuthenticatedAction { implicit request =>
     ...
   }
} 
 0
Author: NKM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-02 07:12:40