Comment faire une propriété à Kotlin qui a un getter privé (ou tout simplement ne pas l'avoir) mais qui a un setter public?
var status
private get
ne fonctionne pas avec une erreur: Getter visibility must be the same as property visibility
Dans mon cas, la raison en est Java interop: je veux que mon code Java puisse appeler setStatus
mais pas getStatus
.
Il est impossible pour le moment à Kotlin d'avoir une propriété avec un setter plus visible que la propriété. Il y a un problème de conception de langue dans le suivi des problèmes à ce sujet, n'hésitez pas à le regarder/voter ou à partager vos cas d'utilisation: https://youtrack.jetbrains.com/issue/KT-311
Dans la version actuelle de Kotlin (1.0.3), la seule option est d'avoir une méthode setter séparée comme ceci:
class Test {
private var name: String = "name"
fun setName(name: String) {
this.name = name
}
}
Si vous souhaitez empêcher les bibliothèques externes d'accéder au getter, vous pouvez utiliser le modificateur de visibilité internal
vous permettant de continuer à utiliser la syntaxe des propriétés dans la bibliothèque:
class Test {
internal var name: String = "name"
fun setName(name: String) { this.name = name }
}
fun usage(){
val t = Test()
t.name = "New"
}
Des propriétés en écriture seule avec des erreurs de compilation peut être obtenues depuis Kotlin 1.0, en utilisant une solution de contournement basée sur @Deprecated
.
Kotlin permet de marquer les fonctions obsolètes avec le niveau ERROR
, ce qui conduit à une erreur de compilation lors de l'appel. Annoter l'accessoire get
d'une propriété comme obsolète , combiné avec un champ de support (afin que les lectures privées soient toujours possibles), atteint le comportement souhaité:
class WriteOnly {
private var backing: Int = 0
var property: Int
@Deprecated("Property can only be written.", level = DeprecationLevel.ERROR)
get() = throw NotImplementedError()
set(value) { backing = value }
val exposed get() = backing // public API
}
Usage:
val wo = WriteOnly()
wo.property = 20 // write: OK
val i: Int = wo.property // read: compile error
val j: Int = wo.exposed // read value through other property
L'erreur de compilation est également très utile:
L'utilisation de "getter pour la propriété: Int" est une erreur. La propriété ne peut être écrite.
Le cas d'utilisation principal est évidemment les API qui permettent d'écrire des propriétés, mais pas de les lire:
user.password = "secret"
val pw = user.password // forbidden
Un autre scénario est une propriété qui modifie l'état interne, mais n'est pas elle-même stockée en tant que champ. (Pourrait être fait plus élégamment en utilisant un design différent).
body.thrust_force = velocity
body.gravity_force = Vector(0, 0, 9.8)
// only total force accessible, component vectors are lost
val f = body.forces
Ce modèle est également utile pour les DSL du type suivant:
server {
port = 80
Host = "www.example.com"
}
Dans de tels cas, les valeurs sont simplement utilisées comme paramètres uniques, et le mécanisme d'écriture seule décrit ici peut empêcher la lecture accidentelle d'une propriété (qui pourrait ne pas encore être initialisée).
Étant donné que cette fonctionnalité n'a pas été conçue pour ce cas d'utilisation, elle comporte certaines limitations:
Si vous y accédez à l'aide d'une référence de propriété, l'erreur de compilation se transforme en erreur d'exécution:
val ref = wo::property
val x = ref.get() // throws NotImplementedError
Il en va de même pour la réflexion.
Cette fonctionnalité ne peut pas être externalisée dans un délégué, car une méthode obsolète getValue()
ne peut pas être utilisée avec by
.