web-dev-qa-db-fra.com

Appelez le constructeur de la super classe à Kotlin, Super n'est pas une expression

J'ai deux classes Entity et Account comme 

abstract class Entity(
    var id: String? = null,
    var created: Date? = Date()) {

    constructor(entity: Entity?) : this() {
        fromEntity(entity)
    }

    fun fromEntity(entity: Entity?): Entity {
        id = entity?.id
        created = entity?.created
        return this;
    }
}

et 

data class Account( 
    var name: String? = null,
    var accountFlags: Int? = null
) : Entity() {

    constructor(entity: Entity) : this() {
        super(entity)
    }
}

Ce qui me donne l'erreur 

Super n'est pas une expression, il ne peut être utilisé que dans la partie gauche de un point '.'

Pourquoi je ne peux pas faire ça? 

Ce qui suit passera l'erreur de compilation, mais je ne suis pas sûr qu'elle soit correcte.

 constructor(entity: Entity) : this() {
    super.fromEntity(entity)
}
14
Amr ElAdawy

Vous avez quelques problèmes dans votre code.

Tout d’abord, c’est la syntaxe correcte pour appeler un super constructeur à partir d’un constructeur secondaire:

constructor(entity: Entity) : super(entity)

Deuxièmement, vous ne pouvez pas appeler un super constructeur depuis un constructeur secondary si votre classe a un constructeur primary (ce que votre classe possède).

Solution 1

abstract class Entity(
        var id: String,
        var created: Date
)

class Account(
        var name: String,
        var accountFlags: Int,
        id: String,
        created: Date
) : Entity(id, created) {
    constructor(account: Account) : this(account.name, account.accountFlags, account.id, account.created)
}

Ici, le constructeur de copie est dans la classe enfant qui délègue simplement le constructeur principal.

Solution 2

abstract class Entity(
        var id: String,
        var created: Date
) {
    constructor(entity: Entity) : this(entity.id, entity.created)
}

class Account : Entity {
    var name: String
    var accountFlags: Int

    constructor(name: String, accountFlags: Int, id: String, created: Date) : super(id, created) {
        this.name = name
        this.accountFlags = accountFlags
    }

    constructor(account: Account) : super(account) {
        this.name = account.name
        this.accountFlags = account.accountFlags
    }
}

Ici, je n'utilise que des constructeurs secondaires dans la classe enfant, ce qui me permet de les déléguer à des super constructeurs individuels. Remarquez comme le code est assez long.

Solution 3 (le plus idiomatique)

abstract class Entity {
    abstract var id: String
    abstract var created: Date
}

data class Account(
        var name: String,
        var accountFlags: Int,
        override var id: String,
        override var created: Date
) : Entity()

Ici, j'ai omis les constructeurs de copie et rendu les propriétés abstraites afin que la classe enfant possède toutes les propriétés. J'ai également fait de la classe enfant un data class. Si vous avez besoin de cloner la classe, vous pouvez simplement appeler account.copy().

34
Kirill Rakhman

Utilisez cette super<Entity>.fromEntity(entity) pour appeler des méthodes de super classe.

Comme le dit la documentation:

En Kotlin, l'héritage d'implémentation est régi par la règle suivante: si une classe hérite de plusieurs implémentations du même membre de ses superclasses immédiates, elle doit remplacer ce membre et fournir sa propre implémentation (peut-être en utilisant l'une des héritées). Pour désigner le supertype dont est issue l'implémentation héritée, nous utilisons super qualifié par le nom du supertype entre crochets angulaires, par ex. super.

constructor(entity: Entity) : this() {
    super<Entity>.fromEntity(entity)
}

Pour en savoir plus lire Règles primordiales

0
chandil03