J'apprends encore Scala, mais une chose que j'ai trouvée intéressante est que Scala brouille la frontière entre les méthodes et les champs. Par exemple, je peux construire une classe comme ça ...Propriétés de Scala Question
class MutableNumber(var value: Int)
La clé ici est que le var dans le constructeur argument me permet automatiquement d'utiliser le champ « valeur » comme un getter/setter en java.
// use number...
val num = new MutableNumber(5)
num.value = 6
println(num.value)
Si je veux ajouter des contraintes, je peux le faire en passant à l'aide de méthodes en place de l'instance champs:
// require all mutable numbers to be >= 0
class MutableNumber(private var _value: Int) {
require(_value >= 0)
def value: Int = _value
def value_=(other: Int) {
require(other >=0)
_value = other
}
}
Le code côté client ne se casse pas depuis l'API doesn « t changer:
// use number...
val num = new MutableNumber(5)
num.value = 6
println(num.value)
Mon raccrochage est avec la fonction de paramètre nommé qui a été ajouté à Scala 2.8. Si j'utilise named-parameters, mon API change et le code casse l'API.
val num = new MutableNumber(value=5) // old API
val num = new MutableNumber(_value=5) // new API
num.value = 6
println(num.value)
Y at-il une solution élégante à cela? Comment dois-je concevoir ma classe MutableNumber pour pouvoir ajouter des contraintes plus tard sans casser l'API?
Merci!
Intéressant! Donc, en cachant le constructeur, je force tout le monde à utiliser l'objet compagnon. Et si je voulais faire de MutableInteger un cas particulier?Je sais que si je mets simplement 'case' devant la définition de classe, Scala crée automatiquement l'objet compagnon pour moi ... cette solution fonctionnerait-elle toujours? – shj
Oui, si vous avez un objet compagnon explicitement défini pour une classe de cas, alors les membres de cet objet seront fusionnés dans celui-ci (et peuvent remplacer, si par exemple vous voulez fournir une méthode 'Companion.apply()' modifiée mais gardez l'autogenerated 'unfapply'). –
@shj - Non, cela ne fonctionnerait pas car les classes de cas assument un accès direct (non gardé) aux variables du constructeur. Vous faites cela parce que vous voulez des gardes (sous la forme de 'require (_value> = 0)' dans ce cas). –