@MarioGalic a répondu à cette question. Je me contenterai de faire quelques ajouts qui sont trop longs pour les commentaires.
Le malentendu le plus courant est que i
en
class MyClass(i : Int)
n'est qu'un paramètre du constructeur et non un champ. En fait, si nous faisons
import scala.reflect.runtime.universe._
println(reify{
class MyClass(i : Int)
}.tree)
nous verrons (Scala 2.13.2)
{
class MyClass extends AnyRef {
<paramaccessor> private[this] val i: Int = _;
def <init>(i: Int) = {
super.<init>();
()
}
};
()
}
Ainsi, un paramètre du constructeur primaire sans val
/ var
génère private[this]
domaine. Ainsi, le
class MyClass(i : Int)
est similaire à
class MyClass(private[this] val i : Int)
et n'est PAS similaire à la fonction
public class MyClass {
public MyClass(int i) {
}
}
sans champs.
Nous pouvons vérifier que i
est un champ qui s'y réfère avec this
dans le corps de la classe
class MyClass(i : Int) {
println(this.i)
}
new MyClass(1) // prints 1
Le champ i
est private[this]
nous ne pouvons donc pas y faire référence en dehors du corps de la classe (ou à l'intérieur du corps sur une instance différente de this
)
class MyClass(i : Int) {
//println(new MyClass(2).i) //doesn't compile
}
//new MyClass(1).i //doesn't compile
Je n'ai pas trouvé de place appropriée dans la spécification de Scala mais ce comportement est bien connu depuis longtemps. Par exemple, dans "Scala for the impatient" de Cay S. Horstmann, il est écrit (édition 2, section 5.7) :
Les paramètres de construction peuvent également être des paramètres de méthode ordinaires, sans qu'il soit nécessaire de les modifier. val
o var
. Le traitement de ces paramètres dépend de leur utilisation dans la classe.
-
Si un paramètre sans val
o var
est utilisé dans au moins une méthode, il devient un champ. Par exemple,
class Person(name: String, age: Int) {
def description = name + " is " + age + " years old"
}
déclare et initialise des champs immuables name
y age
qui sont privés d'objet. Un tel champ est l'équivalent d'un private[this] val
(voir section 5.4, "Champs privés d'objets", à la page 56).
-
Dans le cas contraire, le paramètre n'est pas enregistré en tant que champ. C'est juste un paramètre normal auquel on peut accéder dans le code du constructeur primaire. (À proprement parler, il s'agit d'une optimisation spécifique à l'implémentation).
En fait, dans la version 2.13.2, je ne peux pas confirmer le deuxième cas.
Nous avons maintenant deux classes.
Scala n'autorise pas
class Superclass {
val i: Int = 1
}
class Subclass extends Superclass {
//val i: Int = 2 //doesn't compile
}
à moins que nous n'ajoutions override
class Superclass {
val i: Int = 1
}
class Subclass extends Superclass {
override val i: Int = 2
}
Mais si Superclass
Le champ d'application de la loi est private[this]
tout va bien sans override
class Superclass {
private[this] val i: Int = 1
}
class Subclass extends Superclass {
val i: Int = 2
}
En fait, si nous essayons d'ajouter override
cela ne se compilera pas.
La raison en est qu'il n'est pas prioritaire. L'un des champs est private[this]
c'est-à-dire qu'il n'est pas accessible en dehors de l'objet dans lequel le champ est défini, il s'agit donc de deux champs différents :
class Superclass {
private[this] val i: Int = 1
}
class Subclass extends Superclass {
val i: Int = 2
println(this.i) // or just println(i)
// println((this: Superclass).i) //doesn't compile
}
new Subclass
//2
o
class Superclass {
val i: Int = 1
}
class Subclass extends Superclass {
private[this] val i: Int = 2
println(this.i) // or just println(i)
println((this: Superclass).i)
}
new Subclass
//2
//1
Ainsi, dans notre cas
class Superclass(var i : Int)
class Subclass(i : Int) extends Superclass(0)
sont comme
class Superclass extends AnyRef {
var i: Int = _
def this(_i: Int) = {
super() //pseudocode
i = _i
}
}
class Subclass extends Superclass {
private[this] val i: Int = _ //pseudocode
def this(_i: Int) = {
super(0) //pseudocode
i = _i //pseudocode because "i" is a val -- well, compiler can do things that we can't do in source code
}
}
A l'intérieur Subclass
this.i
ou simplement i
se réfère à Subclass
Le domaine de la private[this] val i: Int
y (this: Superclass).i
se réfère à Superclass
Le domaine de la var i: Int
.
Est-ce que les paramètres des constructeurs scala prennent par défaut la valeur private ?
Paramètres du constructeur Scala
https://www.scala-lang.org/old/node/8384.html