parameters du constructeur de classe scala

Quelle est la différence entre:

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

et

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

Puis-je déclarer des parameters en tant que var s et modifier leurs valeurs plus tard? Par exemple,

 class Person(var name: Ssortingng, var age: Int) { age = happyBirthday(5) def happyBirthday(n: Int) { println("happy " + n + " birthday") n } } 

Pour la première partie, la réponse est la scope:

 scala> class Person(name: Ssortingng, age: Int) { | def say = "My name is " + name + ", age " + age | } scala> val x = new Person("Hitman", 40) scala> x.name :10: error: value name is not a member of Person x.name 

Si vous préfixez des parameters avec val , var ils seront visibles en dehors 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: Ssortingng, val age: Int) 

rend les champs disponibles en externe pour les utilisateurs de la classe, par exemple vous pouvez faire plus tard

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

Si vous spécifiez les arguments comme var , la scope est la même que pour val , mais les champs sont mutables.

Si vous êtes familier avec Java, vous pouvez avoir l’idée de cet exemple:

 class Person(name: Ssortingng, age: Int) 

est similaire à

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

Tandis que

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

est similaire à

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

L’intuition est que sans var / val, la variable n’est accessible qu’à l’intérieur du 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 à celle-ci en explorant le code d’octet. Lorsque vous appliquez javap sur une classe, il imprime les champs et les méthodes des classes, des paquets, des champs protégés et publics. J’ai créé une classe Person.scala et l’ai remplie avec le code suivant.

 class Person(name: Ssortingng, age: Int) { def say = "My name is " + name + ", age " + age } class PersonVal(val name: Ssortingng, val age: Int) { def say = "My name is " + name + ", age " + age } class PersonVar(var name: Ssortingng, 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 il génère trois fichiers avec les noms Person.class, PersonVal.calass , PersonVar.cass . En exécutant javap pour chacun de ces fichiers de classe, nous pouvons voir comment la structure serait:

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

Dans ce cas, il n’a pas créé de classe varible pour Person car elle est déclarée sans val, ni val, donc le nom et l’âge ne peuvent être utilisés qu’à l’intérieur du constructeur.

 >>javap PersonVal.class public class PersonVal { public java.lang.Ssortingng name(); public int age(); public java.lang.Ssortingng say(); public PersonVal(java.lang.Ssortingng, int); } 

Dans ce cas, il a trois membres deux pour le constructeur d’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, donc nous ne pouvons pas modifier les valeurs.

 >>javap PersonVar.class public class PersonVar { public java.lang.Ssortingng name(); public void name_$eq(java.lang.Ssortingng); public int age(); public void age_$eq(int); public int happyBirthday(int); public PersonVar(java.lang.Ssortingng, int); } 

C’est la même chose que l’exemple PersonVal mais nous pouvons changer les valeurs dans ce cas avec les méthodes variable_$eq . il n’y a rien qu’une version raccourcie de variable =

Vous pourriez utiliser une case class et, dans ce cas, la classe Person aurait ces variables disponibles en dehors de la classe. case class Person(name: Ssortingng, age: Int) . Le code suivant fonctionnerait alors comme prévu. val z = new Person("John", 20); z.name //John

La réponse de @Reza, où l’auteur explore le code d’octet en utilisant javap, m’a aidé à clarifier ce concept. 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 Web de production (Play + Scala): Comment injecter des parameters dans une méthode de classe / trait dans Scala

Si je n’utilise pas le préfixe val dans le paramètre injecté authorizationHandler le compilateur renvoie 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, cette erreur ne m’a pas aidé à identifier le problème qui consiste à préfixer val .

 class MyController @Inject()(val authorizationHandler: AuthorizationHandler) extends Controller with AuthorizationCheck { def myAction = AuthenticatedAction { implicit request => ... } }