J'ai aimé la réponse de Roland Ewald car il a décrit avec un cas d'utilisation très simple d'alias de type et pour plus de détails, a introduit un tutoriel très sympa. Cependant, comme un autre cas d'utilisation est introduit dans ce post appelé membres de type, je voudrais mentionner le cas d'utilisation le plus pratique, que j'ai beaucoup aimé : (cette partie est tirée de ici:)
Type Abstrait :
type T
Le T ci-dessus dit que ce type qui va être utilisé est encore inconnu et dépendra de la sous-classe concrète dans laquelle il sera défini. La meilleure façon de toujours comprendre les concepts de programmation est de fournir un exemple : Supposons que vous ayez le scénario suivant :
Ici, vous obtiendrez une erreur de compilation, car la méthode eat dans les classes Cow et Tiger ne substitue pas la méthode eat dans la classe Animal, car leurs types de paramètres sont différents. C'est Grass dans la classe Cow et Meat dans la classe Tiger vs. Food dans la classe Animal qui est la super classe et toutes les sous-classes doivent s'y conformer.
Revenons maintenant à l'abstraction de type, avec le diagramme suivant et en ajoutant simplement une abstraction de type, vous pouvez définir le type de l'entrée dans la sous-classe correspondante.
Regardez maintenant le code suivant :
val cow1: Cow = new Cow
val cow2: Cow = new Cow
cow1 eat new cow1.SuitableFood
cow2 eat new cow1.SuitableFood
val tiger: Tiger = new Tiger
cow1 eat new tiger.SuitableFood // Erreur de compilation
Le compilateur est content et nous améliorons notre conception. Nous pouvons nourrir notre vache avec la cow.SuitableFood et le compilateur nous empêche de nourrir notre vache avec la nourriture qui convient au tigre. Mais que se passe-t-il si nous voulons faire la différence entre le type de la cow1 SuitableFood et la cow2 SuitableFood. En d'autres termes, ce serait très pratique dans certains scénarios si le chemin par lequel nous accédons au type (bien sûr via un objet) importait fondamentalement. Grâce aux fonctionnalités avancées de Scala, c'est possible :
Types Dépendants du Chemin : Les objets Scala peuvent avoir des types en tant que membres. La signification du type dépend du chemin que vous utilisez pour y accéder. Le chemin est déterminé par la référence à un objet (alias une instance d'une classe). Pour mettre en œuvre ce scénario, vous devez définir la classe Grass à l'intérieur de Cow, c'est-à-dire, Cow est la classe externe et Grass est la classe interne. La structure sera comme suit :
class Cow extends Animal {
class Grass extends Food
type SuitableFood = Grass
override def eat(food: this.SuitableFood): Unit = {}
}
class Tiger extends Animal {
class Meat extends Food
type SuitableFood = Meat
override def eat(food: this.SuitableFood): Unit = {}
}
Si vous essayez maintenant de compiler ce code :
1. val cow1: Cow = new Cow
2. val cow2: Cow = new Cow
3. cow1 eat new cow1.SuitableFood
4. cow2 eat new cow1.SuitableFood // erreur de compilation
À la ligne 4, vous verrez une erreur car Grass est maintenant une classe interne de Cow, donc pour créer une instance de Grass, nous avons besoin d'un objet cow et cet objet cow détermine le chemin. Ainsi, 2 objets cow donnent lieu à 2 chemins différents. Dans ce scénario, cow2 veut seulement manger de la nourriture spécialement créée pour elle. Donc :
cow2 eat new cow2.SuitableFood
Maintenant tout le monde est content :-)