161 votes

Comprendre ce que fait le mot-clé 'type' en Scala

Je suis nouveau en Scala et je n'ai pas vraiment trouvé beaucoup d'informations sur le mot clé type. J'essaie de comprendre ce que pourrait signifier l'expression suivante :

type FunctorType = (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate

FunctorType est une sorte d'alias, mais que signifie-t-il ?

215voto

Marius Danila Points 5075

En fait, le mot-clé type en Scala peut faire beaucoup plus que simplement donner un alias à un type compliqué avec un nom plus court. Il introduit des membres de type .

Comme vous le savez, une classe peut avoir des membres de champ et des membres de méthode. Eh bien, Scala permet également à une classe d'avoir des membres de type.

Dans votre cas particulier, type introduit en effet un alias qui vous permet d'écrire un code plus concis. Le système de types remplace simplement l'alias par le type réel lors de la vérification du type.

Mais vous pouvez aussi avoir quelque chose comme ceci

trait Base {
  type T

  def method: T
}

class Implementation extends Base {
  type T = Int

  def method: T = 42
}

Comme tout autre membre d'une classe, les membres de type peuvent également être abstraits (vous ne spécifiez tout simplement pas quelle est leur valeur réelle) et peuvent être remplacés dans les implémentations.

Les membres de type peuvent être vus comme étant le dual des génériques, car de nombreuses choses que vous pouvez implémenter avec des génériques peuvent être traduites en membres de type abstraits.

Donc oui, ils peuvent être utilisés pour donner un alias, mais ne les limitez pas à cela, car ils sont une fonctionnalité puissante du système de types de Scala.

Veuillez consulter cette excellente réponse pour plus de détails:

Scala: Types abstraits vs génériques

167voto

Ronda Points 11

Oui, l'alias de type FunctorType est juste un raccourci pour

(LocalDate, HolidayCalendar, Int, Boolean) => LocalDate

Les alias de type sont souvent utilisés pour simplifier le reste du code : vous pouvez maintenant écrire

def doSomeThing(f: FunctorType)

qui sera interprété par le compilateur comme

def doSomeThing(f: (LocalDate, HolidayCalendar, Int, Boolean) => LocalDate)

Cela aide à éviter de définir de nombreux types personnalisés qui ne sont que des tuples ou des fonctions définies sur d'autres types, par exemple.

Il existe également plusieurs autres cas d'utilisation intéressants pour type, comme décrit par exemple dans ce chapitre de Programming in Scala.

16voto

Mehran Points 271

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 :

Sans Abstraction de Type

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.

Avec Type Abstrait

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 :-)

5voto

Juste un exemple pour voir comment utiliser "type" en tant qu'alias :

type Action = () => Unit

La définition ci-dessus définit Action comme un alias du type de procédures (méthodes) qui prennent une liste de paramètres vides et qui retournent Unit.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X