Remplacer getter pour Kotlin classe de données
Le suivant Kotlin classe:
data class Test(val value: Int)
Comment pourrais-je remplacer la Int
de lecture de sorte qu'elle retourne 0 si la valeur négative?
Si ce n'est pas possible, ce sont quelques techniques pour obtenir un résultat convenable?
- Veuillez envisager de modifier la structure de votre code, de sorte que les valeurs négatives sont converties à 0 lorsque la classe est instanciée, et pas dans un getter. Si vous remplacez la lecture comme indiqué dans la réponse ci-dessous, toutes les autres méthodes générées comme equals(), toString() et le composant d'accès utilise toujours le négatif original de la valeur, ce qui mènera probablement à un comportement surprenant.
Vous devez vous connecter pour publier un commentaire.
Après avoir passé près d'une année complète de la rédaction de Kotlin au quotidien, j'ai trouvé que le fait de chercher à remplacer les classes de données comme c'est une mauvaise pratique. Il y a 3 approches valables pour le présent, et après je leur présente, je vais vous expliquer pourquoi l'approche d'autres réponses ont suggéré est mauvais.
Ont une logique d'entreprise qui crée la
data class
modifier la valeur à 0 ou plus avant d'appeler le constructeur de la mauvaise valeur. C'est probablement la meilleure approche pour la plupart des cas.N'utilisez pas de
data class
. L'utilisation régulière d'unclass
et votre IDE générer laequals
ethashCode
méthodes pour vous (ou pas, si vous n'en avez pas besoin). Oui, vous allez avoir à re-générer si les propriétés sont modifiées sur l'objet, mais vous êtes de gauche avec un contrôle total de l'objet.Créer un nouveau coffre-fort à la propriété sur l'objet qui fait ce que vous voulez au lieu d'avoir une valeur privée c'est effectivement surchargé.
Une mauvaise approche que d'autres réponses sont ce qui suggère:
Le problème avec cette approche est que classes de données ne sont pas vraiment conçus pour modifier les données de ce genre. Ils sont vraiment simplement pour conserver les données. Primordial de la lecture pour une classe de données comme cela signifierait que
Test(0)
etTest(-1)
ne serait pasequal
l'un de l'autre et auraient des différentshashCode
s, mais quand vous avez appelé.value
, ils auraient le même résultat. C'est incohérent, et tandis qu'il peut travailler pour vous, d'autres personnes dans votre équipe qui a le voir c'est une classe de données, peut accidentellement en abuser sans se rendre compte de la façon dont vous avez modifié /le fait de ne pas fonctionner comme prévu (c'est à dire que cette approche ne fonctionne pas correctement dans unMap
ou unSet
).data class class(@JsonProperty("iss_position") private val position: Map<String, Double>) { val latitude = position["latitude"]; val longitude = position["longitude"] }
, et je considère qu'il est très bon pour mon cas, tbh. Que pensez-vous de cela? (il y avait de l'ofc d'autres domaines, et donc je crois qu'il n'a pas de sens pour moi de recréer qui nichaient structure json dans mon code)parsing a string into an int
, vous êtes clairement en permettant à l'entreprise de la logique de l'analyse et la gestion des erreurs non-Chaînes numériques dans votre modèle de classe...List
etMutableList
pour aucune raison.Vous pouvez essayer quelque chose comme ceci:
Dans une classe de données, vous devez marquer le principal paramètres du constructeur, soit avec
val
ouvar
.Je suis d'affecter la valeur de
_value
àvalue
afin d'utiliser le nom souhaité pour le bien.J'ai défini une coutume accesseur pour le bien avec la logique que vous avez décrit.
La réponse dépend de ce que les capacités que vous utilisez réellement que
data
fournit. @EPadron mentionné un truc astucieux (version améliorée):Qui fonctionne comme prévu, l'e.i il a un champ, un getter, droit
equals
,hashcode
etcomponent1
. Le hic, c'est quetoString
etcopy
sont bizarre:De résoudre le problème avec
toString
vous pouvez redéfinir par les mains. Je ne connais pas de moyen pour régler le paramètre de nommage, mais de ne pas utiliserdata
à tous.Je sais que c'est une vieille question, mais il semble que personne n'a mentionné la possibilité de faire de la valeur privée et de l'écriture personnalisée getter comme ceci:
Ce doit être parfaitement valable que Kotlin ne générera pas de défaut de lecture pour le domaine privé.
Mais sinon, je suis absolument d'accord avec spierce7 que les classes de données sont pour la tenue des données et vous devriez éviter de coder en dur "métier" il.
Ce qui semble être une (parmi d'autres) inconvénients gênants de Kotlin.
Il semble que la seule solution raisonnable, ce qui maintient la compatibilité descendante de la classe est de le convertir en une classe ordinaire (pas un "données" de la classe), et de mettre en œuvre à la main (avec l'aide de l'IDE) les méthodes: les méthodes hashCode(), equals(), toString(), copy() et componentN()
J'ai trouvé le suivant à être la meilleure approche pour obtenir ce dont vous avez besoin sans casser
equals
ethashCode
:Cependant,
Tout d'abord, notez que
_value
estvar
, pasval
, mais d'un autre côté, vu que c'est privé et classes de données ne peut pas être héritée d', il est assez facile de s'assurer qu'il n'est pas modifié à l'intérieur de la classe.Deuxième,
toString()
produit un résultat légèrement différent si_value
a été nommévalue
, mais c'est cohérent etTestData(0).toString() == TestData(-1).toString()
._value
est en cours de modification dans l'init de bloc etequals
ethashCode
ne sont pas rompus.