Quelle est la différence entre:
class Person(name: String, age: Int) {
def say = "My name is " + name + ", age " + age
}
et
class Person(val name: String, val age: Int) {
def say = "My name is " + name + ", age " + age
}
Puis-je déclarer des paramètres en tant que var
s et modifier leurs valeurs ultérieurement? Par exemple,
class Person(var name: String, var age: Int) {
age = happyBirthday(5)
def happyBirthday(n: Int) {
println("happy " + n + " birthday")
n
}
}
Pour la première partie, la réponse est portée:
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
Si vous préfixez les paramètres avec val
, var
, ils seront visibles de l'extérieur de la classe, sinon ils seront privés, comme vous pouvez le voir dans le code ci-dessus.
Et oui, vous pouvez changer la valeur de la variable, comme d'habitude.
Ce
class Person(val name: String, val age: Int)
rend les champs disponibles en externe pour les utilisateurs de la classe, par ex. tu peux faire plus tard
val p = new Person("Bob", 23)
val n = p.name
Si vous spécifiez les arguments sous la forme var
, la portée est la même que pour val
, mais les champs sont mutables.
Si vous connaissez Java, vous pouvez vous faire une idée à partir de cet exemple:
class Person(name: String, age: Int)
est semblable à
class Person {
public Person(String name, int age) {
}
}
Tandis que
class Person(var name: String, var age: Int) // also we can use 'val'
est similaire à
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
L'intuition est que sans var/val, la variable n'est accessible que dans le constructeur. Si var/val est ajouté, la classe aura les variables membres avec le même nom.
Les réponses ici sont vraiment bonnes, mais je m'attaque à celui-ci en explorant le code d'octet. Lorsque vous appliquez javap
sur une classe, celle-ci imprime les champs de package, protégés et publics ainsi que les méthodes des classes transmises. J'ai créé une classe Person.scala et l'ai complétée avec le code suivant.
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
}
}
Après avoir compilé le code avec scalac Person.scala
, trois fichiers portant le nom Person.class, PersonVal.calass , PersonVar.cass
sont générés. En exécutant javap
pour chacun de ces fichiers de classe, nous pouvons voir comment la structure serait:
>>javap Person.class
Compiled from "Person.scala"
public class Person {
public Java.lang.String say();
public Person(Java.lang.String, int);
}
Dans ce cas, il n'a créé aucune classe variable pour Person car il est déclaré avec ni val, ni val, donc name et age peuvent uniquement être utilisés dans le constructeur.
>>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);
}
Dans ce cas, il a trois membres, deux pour le constructeur en entrée et un pour le membre que nous avons déclaré dans le constructeur. Cependant, nous n'avons pas de setter pour les constructeurs d'entrée, nous ne pouvons donc pas changer les valeurs.
>>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);
}
C'est la même chose que l'exemple PersonVal mais nous pouvons changer les valeurs dans ce cas avec ces méthodes variable_$eq
. il n'y a rien qu'une version abrégée de variable =
La réponse de @Reza où l'auteur explore le code d'octet à l'aide de javap m'a aidé à clarifier ce concept au mieux. Pour citer un exemple très spécifique de ce cas, veuillez vous reporter au scénario ci-dessous que j'ai rencontré dans mon application de production Web (Play + Scala): Comment injecter des paramètres dans une méthode de classe/trait dans Scala
Si je n'utilise pas le préfixe val pour injecter le paramètre authorizationHandler
, alors Compiler lève cette erreur:
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
Malheureusement, l'erreur ne m'a pas aidé à identifier le problème correct, à savoir préfixer avec val
.
class MyController @Inject()(val authorizationHandler: AuthorizationHandler) extends Controller with AuthorizationCheck {
def myAction = AuthenticatedAction { implicit request =>
...
}
}