it-swarm-eu.dev

Utilisation de def, val et var dans scala

class Person(val name:String,var age:Int )
def person = new Person("Kumar",12)
person.age = 20
println(person.age)

Ces lignes de code génèrent 12, Même si person.age=20 A été exécuté avec succès. J'ai trouvé que cela se produit parce que j'ai utilisé def dans def person = new Person("Kumar",12). Si j'utilise var ou val, le résultat est 20. Je comprends que la valeur par défaut est val in scala. Cette:

def age = 30
age = 45

... donne une erreur de compilation car c'est un val par défaut. Pourquoi le premier ensemble de lignes ci-dessus ne fonctionne-t-il pas correctement et pourtant n'erreur pas?

146
Byju Veedu

Il y a trois façons de définir les choses dans Scala:

  • def définit une méthode
  • val définit une valeur fixe valeur (qui ne peut pas être modifiée)
  • var définit une variable (qui peut être modifiée)

En regardant votre code:

def person = new Person("Kumar",12)

Ceci définit une nouvelle méthode appelée person. Vous pouvez appeler cette méthode uniquement sans () car il est défini comme une méthode sans paramètre. Pour la méthode empty-paren, vous pouvez l'appeler avec ou sans '()'. Si vous écrivez simplement:

person

alors vous appelez cette méthode (et si vous n'attribuez pas la valeur de retour, elle sera simplement supprimée). Dans cette ligne de code:

person.age = 20

ce qui se passe, c'est que vous appelez d'abord la méthode person et que vous modifiez la variable membre Person sur la valeur de retour (une instance de classe age).

Et la dernière ligne:

println(person.age)

Ici, vous appelez à nouveau la méthode person, qui renvoie une nouvelle instance de classe Person (avec age défini sur 12). C'est pareil que ça:

println(person().age)
239
Jesper

Je commencerais par la distinction qui existe dans Scala entre def, val et var.

  • def - définit une étiquette immuable pour le contenu du côté droit qui est évalué paresseusement - à évaluer par Nom.

  • val - définit une étiquette immuable pour le contenu de droite qui est évalué avant/immédiatement - évalué par la valeur.

  • var - définit une variable mutable , initialement définie sur le contenu du côté droit évalué.

Exemple, def

scala> def something = 2 + 3 * 4 
something: Int
scala> something  // now it's evaluated, lazily upon usage
res30: Int = 14

Exemple, val

scala> val somethingelse = 2 + 3 * 5 // it's evaluated, eagerly upon definition
somethingelse: Int = 17

Exemple, var

scala> var aVariable = 2 * 3
aVariable: Int = 6

scala> aVariable = 5
aVariable: Int = 5

Selon ce qui précède, les étiquettes de def et val ne peuvent pas être réaffectées et, en cas de tentative, une erreur comme celle ci-dessous sera générée:

scala> something = 5 * 6
<console>:8: error: value something_= is not a member of object $iw
       something = 5 * 6
       ^

Quand la classe est définie comme:

scala> class Person(val name: String, var age: Int)
defined class Person

puis instancié avec:

scala> def personA = new Person("Tim", 25)
personA: Person

un étiquette immuable est créé pour cette instance spécifique de Person (c'est-à-dire 'personA'). Chaque fois que le champ mutable 'age' doit être modifié, cette tentative échoue:

scala> personA.age = 44
personA.age: Int = 25

comme prévu, 'age' fait partie d'une étiquette non-mutable. La bonne façon de travailler consiste à utiliser une variable mutable, comme dans l'exemple suivant:

scala> var personB = new Person("Matt", 36)
personB: Person = [email protected]

scala> personB.age = 44
personB.age: Int = 44    // value re-assigned, as expected

en clair, à partir de la référence de variable mutable (c'est-à-dire 'personB'), il est possible de modifier le champ mutable de classe 'age'.

Je voudrais encore souligner le fait que tout vient de la différence indiquée ci-dessus, cela doit être clair dans l'esprit de tout programmeur Scala.

92
Paolo Maresca

Avec

def person = new Person("Kumar", 12) 

vous définissez une variable fonction/lazy qui renvoie toujours une nouvelle instance Person nommée "Kumar" et âgée de 12 ans. Ceci est tout à fait valable et le compilateur n’a aucune raison de se plaindre. L'appel de person.age renverra l'âge de cette instance Person nouvellement créée, qui est toujours de 12 ans.

En écrivant

person.age = 45

vous affectez une nouvelle valeur à la propriété age dans la classe Person, qui est valide car age est déclaré comme var. Le compilateur se plaindra si vous essayez de réaffecter person avec un nouvel objet Personne comme

person = new Person("Steve", 13)  // Error
29
Kintaro

Pour fournir une autre perspective, "def" in Scala signifie quelque chose qui sera sera évalué à chaque fois quand il sera utilisé, alors que val sera quelque chose qui sera évalué immédiatement et seulement une fois. Ici, l'expression def person = new Person("Kumar",12) implique que chaque fois que nous utilisons "personne", nous aurons un appel new Person("Kumar",12). Il est donc naturel que les deux "personne.age" ne sont pas liés.

C'est ainsi que je comprends Scala (probablement d'une manière plus "fonctionnelle"). Je ne sais pas si

def defines a method
val defines a fixed value (which cannot be modified)
var defines a variable (which can be modified)

est vraiment ce que Scala entend bien signifier. Je n'aime pas trop penser ainsi au moins ...

25
xji

Comme Kintaro l'a déjà dit, personne est une méthode (en raison de def) et renvoie toujours une nouvelle instance Person. Comme vous l'avez découvert, cela fonctionnerait si vous changiez la méthode en var ou val:

val person = new Person("Kumar",12)

Une autre possibilité serait:

def person = new Person("Kumar",12)
val p = person
p.age=20
println(p.age)

Toutefois, person.age=20 dans votre code est autorisé, car vous récupérez une instance Person de la méthode person, et vous êtes autorisé à modifier la valeur de var. Le problème est qu’après cette ligne, vous n’avez plus aucune référence à cette instance (car chaque appel à person produira une nouvelle instance).

Ceci n’a rien de spécial, vous auriez exactement le même comportement en Java:

class Person{ 
   public int age; 
   private String name;
   public Person(String name; int age) {
      this.name = name;  
      this.age = age;
   }
   public String name(){ return name; }
}

public Person person() { 
  return new Person("Kumar", 12); 
}

person().age = 20;
System.out.println(person().age); //--> 12
19
Landei

Prenons ceci:

class Person(val name:String,var age:Int )
def person =new Person("Kumar",12)
person.age=20
println(person.age)

et le réécrire avec un code équivalent

class Person(val name:String,var age:Int )
def person =new Person("Kumar",12)
(new Person("Kumar", 12)).age_=(20)
println((new Person("Kumar", 12)).age)

Voir, def est une méthode. Il s'exécutera à chaque appel et à chaque fois qu'il retournera (a) new Person("Kumar", 12). Et ce n'est pas une erreur dans la "tâche" car ce n'est pas vraiment une tâche, mais juste un appel à la méthode age_= (Fournie par var).

8
Daniel C. Sobral