Types structurés (Object Pascal)

De Appmethod Topics
Aller à : navigation, rechercher

Remonter à Types de données, variables et constantes - Index


Les instances d'un type structuré contiennent plusieurs valeurs. Les types structurés sont les types ensemble, tableau, enregistrement, fichier, classe, référence de classe et interface. A l'exception des ensembles qui contiennent uniquement des valeurs ordinales, les types structurés peuvent contenir d'autres types structurés ; un type peut avoir un niveau illimité de structuration.

Cette rubrique traite les types structurés suivants :

  • Ensembles
  • Tableaux, y compris les tableaux statiques et dynamiques
  • Enregistrements
  • Types de fichiers

Alignement des types structurés

Par défaut, les valeurs d'un type structuré sont alignées sur des limites de mot ou de double-mot afin de disposer d'un accès plus rapide.

Toutefois, vous pouvez spécifier l'alignement sur des octets en incluant le mot réservé packed quand vous déclarez un type structuré. Le mot packed spécifie le stockage compressé des données. Voici une déclaration exemple :

 type TNumbers = packed array [1..100] of Real;

L'utilisation de packed n'est pas une pratique recommandée, car elle empêche la compatibilité avec d'autres langages ou plates-formes. Elle ralentit l'accès aux données et, dans le cas d'un tableau de caractères, affecte la compatibilité des types. Pour de plus amples informations, voir Gestion de la mémoire et Alignement packed implicite des champs avec une spécification de type commune.

Ensembles

Un ensemble est une collection de valeurs ayant le même type ordinal. Les valeurs n'ont pas d'ordre intrinsèque, une même valeur ne peut donc pas apparaître deux fois dans un ensemble.

L'étendue d'un type ensemble est l'ensemble puissance d'un type ordinal particulier, appelé le type de base ; c'est-à-dire que les valeurs possibles du type ensemble sont tous les sous-ensembles du type de base, y compris l'ensemble vide. Le type de base ne peut avoir plus de 256 valeurs possibles et leur rang doit être compris entre 0 et 255. Toute construction de la forme :

set of baseType

baseType est un type ordinal approprié, identifie un type ensemble.

En raison des limitations de taille des types de base, les types ensemble sont généralement définis avec des intervalles. Par exemple, les déclarations :

 type
   TSomeInts = 1..250;
   TIntSet = set of TSomeInts;

créent un type d'ensemble appelé TIntSet dont les valeurs sont des collections d'entiers dans l'intervalle 1 à 250. Le même résultat est obtenu avec :

 type TIntSet = set of 1..250;

Etant donné cette déclaration, vous pouvez créer un ensemble de la manière suivante :

 var Set1, Set2: TIntSet;
     ...
     Set1 := [1, 3, 5, 7, 9];
     Set2 := [2, 4, 6, 8, 10]

Vous pouvez également utiliser directement la construction set of ... dans les déclarations des variables :

 var MySet: set of 'a'..'z';
     ...
     MySet := ['a','b','c'];

Voici d'autres exemples de type ensemble :

set of Byte
set of (Club, Diamond, Heart, Spade)
set of Char;

L'opérateur in teste l'appartenance à l'ensemble :

 if 'a' in MySet then ... { do something } ;

Chaque type ensemble peut contenir l'ensemble vide, qui est désigné par []. Pour de plus amples informations sur les ensembles, voir "Définir les constructeurs" et "Définir les opérateurs" dans Expressions (Object Pascal).

Tableaux

Un tableau représente une collection indexée d'éléments de même type (appelé le type de base). Comme chaque élément a un index unique, les tableaux (à la différence des ensembles) peuvent sans ambiguïté contenir plusieurs fois la même valeur. Il est possible d'allouer des tableaux de manière statique ou dynamique.

Tableaux statiques

Les tableaux statiques sont désignés par des constructions de la forme :

array[indexType1, ..., indexTypen] of baseType;

où chaque indexType est un type ordinal dont l'étendue ne doit pas dépasser 2 Go. Comme les indexTypes indexent le tableau, le nombre d'éléments que le tableau peut contenir est limité par le produit des tailles des indexTypes. Pratiquement, les indexTypes sont en général des intervalles d'entiers.

Dans le cas le plus simple d'un tableau à une dimension, il n'y a qu'un seul indexType. Par exemple :

 var MyArray: array [1..100] of Char;

déclare une variable appelée MyArray qui contient un tableau de 100 valeurs caractère. Etant donné cette déclaration, MyArray[3] désigne le troisième caractère de MyArray. Si vous créez un tableau statique sans assigner de valeurs à tous ses éléments, les éléments inutilisés sont néanmoins alloués et contiennent des données aléatoires ; ils sont identiques à des variables non initialisées.

Un tableau à plusieurs dimensions est un tableau de tableaux. Par exemple :

 type TMatrix = array[1..10] of array[1..50] of Real;

est l'équivalent de :

 type TMatrix = array[1..10, 1..50] of Real;

Quelle que soit la manière dont TMatrix est déclaré, ce type représente un tableau de 500 valeurs réelles. Une variable MyMatrix de type TMatrix peut être indexée comme ceci : MyMatrix[2,45]; ou comme cela : MyMatrix[2][45]. De même :

 packed array[Boolean, 1..10, TShoeSize] of Integer;

est l'équivalent de :

 packed array[Boolean] of packed array[1..10] of packed array[TShoeSize] of Integer;

Les fonctions standard Low et High acceptent les variables et les identificateurs de type tableau. Elles renvoient les bornes basse et haute du premier index du type. La fonction standard Length renvoie le nombre d'éléments dans la première dimension du tableau.

Un tableau à une dimension compacté statique de valeurs Char est appelé une chaîne compactée. Les types chaîne compactée sont compatibles avec les types chaîne et avec les autres types de chaîne compactée ayant le même nombre d'éléments. Voir Compatibilité et identité de types.

Un type tableau de la forme array[0..x] of Char est appelé un tableau de caractères à index de base zéro. Ces tableaux sont utilisés pour stocker des chaînes terminées par null et sont compatibles avec les valeurs PChar. Voir "Manipulation des chaînes terminées par null" dans Types chaîne (Object Pascal).

Tableaux dynamiques

Les tableaux dynamiques n'ont pas de taille ni de longueur fixe. La mémoire d'un tableau dynamique est réallouée quand vous assignez une valeur au tableau ou le transmettez à la procédure SetLength. Les types de tableau dynamique sont désignés par des constructions de la forme :

array of baseType

Par exemple :

 var MyFlexibleArray: array of Real;

déclare un tableau dynamique de réels à une dimension. La déclaration n'alloue pas de mémoire à MyFlexibleArray. Pour créer le tableau en mémoire, appelez SetLength. Par exemple, étant donné la déclaration suivante :

 SetLength(MyFlexibleArray, 20);

alloue un tableau de 20 réels indexés de 0 à 19. Une méthode alternative d'allocation de mémoire pour les tableaux dynamiques consiste à invoquer le constructeur de tableau :

 type
   TMyFlexibleArray = array of Integer;
 
 begin
   MyFlexibleArray := TMyFlexibleArray.Create(1, 2, 3 {...});
 end;

qui alloue de la mémoire pour trois éléments et assigne à chaque élément la valeur donnée.

De façon analogue au constructeur de tableau, un tableau dynamique peut également être initialisé à partir d'une expression de constante de tableau, comme ci-dessous.

  procedure MyProc;
  var
    A: array of Integer;
  begin
    A := [1, 2, 3];
  end;

Notez qu'à l'inverse d'un constructeur de tableau, une constante tableau peut être appliquée directement sur un type tableau dynamique non nommé. Cette syntaxe est spécifique aux tableaux dynamiques. L'application de cette technique à d'autres types de tableaux conduirait probablement à l'interprétation de la constante en tant qu'ensemble, déclenchant ainsi une erreur d'incompatibilité de types à la compilation.

Les tableaux dynamiques sont toujours indexés par des entiers, en commençant toujours par 0.

Les variables tableau dynamique sont implicitement des pointeurs et sont gérés par la même technique de comptage de références que celle utilisée pour les chaînes longues. Pour désallouer un tableau dynamique, assignez nil à une variable qui référence le tableau ou transmettez la variable à Finalize ; ces deux méthodes libèrent le tableau dans la mesure où il n'y a pas d'autres références le désignant. Les tableaux dynamiques sont automatiquement libérés lorsque leur compte de références atteint zéro. Les tableaux dynamiques de longueur 0 ont la valeur nil. N'appliquez pas l'opérateur de déréférencement (^) à une variable tableau dynamique et ne la transmettez pas à la procédure New ou Dispose.

Si X et Y sont des variables du même type de tableau dynamique, X := Y fait pointer X sur le même tableau que Y. (Il n'est pas nécessaire d'allouer de la mémoire à X avant d'effectuer cette opération.) A la différence des chaînes et des tableaux statiques, les tableaux dynamiques n'utilisent pas copy-on-write et ils ne sont donc pas automatiquement copiés avant d'être modifiés. Par exemple, après l'exécution du code suivant :

 var
   A, B: array of Integer;
   begin
     SetLength(A, 1);
     A[0] := 1;
     B := A;
     B[0] := 2;
   end;

la valeur de A[0] est 2. (Si A et B étaient des tableaux statiques, A[0] vaudrait toujours 1.)

L'affectation d'un index de tableau dynamique (par exemple, MyFlexibleArray[2] := 7) ne réalloue pas le tableau. Les index hors des bornes ne sont pas détectés à la compilation.

En revanche, pour faire une copie indépendante d'un tableau dynamique, vous devez utiliser la fonction Copy globale :

 var
   A, B: array of Integer;
 begin
   SetLength(A, 1);
   A[0] := 1;
   B := Copy(A);
   B[0] := 2; { B[0] <> A[0] }
 end;

Quand des variables tableau dynamique sont comparées, les références sont comparées et non pas la valeur des tableaux. Donc, après l'exécution du code :

 var
   A, B: array of Integer;
 begin
    SetLength(A, 1);
    SetLength(B, 1);
    A[0] := 2;
    B[0] := 2;
 end;

A = B renvoie False mais A[0] = B[0] renvoie True.

Pour tronquer un tableau dynamique, transmettez-le à SetLength ou à Copy, et réassignez le résultat à la variable tableau. (La procédure SetLength est généralement plus rapide.) Par exemple, si A est un tableau dynamique, les deux lignes suivantes tronquent tout sauf les 20 premiers éléments de A :

 SetLength(A, 20)
 A := Copy(A, 0, 20)

Dès qu'un tableau dynamique a été alloué, vous pouvez le transmettre aux fonctions standard Length, High et Low. Length renvoie le nombre d'éléments du tableau, High renvoie l'index le plus élevé du tableau (c'est-à-dire Length - 1) et Low renvoie 0. Dans le cas d'un tableau de longueur nulle, High renvoie -1 (avec cette anomalie que High < Low).

Remarque : Dans les déclarations de certaines procédures et fonctions, les paramètres tableau sont représentés sous la forme array of baseType, sans spécifier le type d'index. Par exemple, function CheckStrings(A: array of string): Boolean;

Cela indique que la fonction opère sur tous les tableaux du type de base spécifié indépendamment de leur taille, de leurs index ou de leur allocation statique ou dynamique.

Tableaux dynamiques multi-dimensionnels

Pour déclarer des tableaux dynamiques multi-dimensionnels, utilisez des constructions array of ... répétées. Par exemple :

 type TMessageGrid = array of array of string;
 var Msgs: TMessageGrid;

déclare un tableau de chaînes à deux dimensions. Pour instancier ce tableau, appelez SetLength avec deux arguments entiers. Par exemple, si I et J sont des variables de valeurs entières :

 SetLength(Msgs,I,J);

alloue un tableau de I-fois-J et Msgs[0,0] désigne un élément de ce tableau.

Vous pouvez créer des tableaux dynamiques multidimensionnels qui ne sont pas rectangulaires. Il faut tout d'abord appeler SetLength en lui transmettant les paramètres pour les n premières dimensions du tableau. Par exemple :

 var Ints: array of array of Integer;
 SetLength(Ints,10);

alloue dix lignes pour Ints mais pas les colonnes. Ultérieurement, vous pouvez allouer les colonnes une à une (en leur donnant des longueurs différentes) ; par exemple :

 SetLength(Ints[2], 5);

donne la longueur cinq à la troisième colonne de Ints. A ce stade (même si les autres colonnes n'ont pas été allouées), vous pouvez assigner des valeurs à la troisième colonne ; par exemple, Ints[2,4] := 6.

L'exemple suivant utilise un tableau dynamique (et la fonction IntToStr déclarée dans l'unité SysUtils) pour créer une matrice triangulaire de chaînes.

 var
   A : array of array of string;
   I, J : Integer;
 begin
   SetLength(A, 10);
   for I := Low(A) to High(A) do
   begin
     SetLength(A[I], I);
     for J := Low(A[I]) to High(A[I]) do
       A[I,J] := IntToStr(I) + ',' + IntToStr(J) + ' ';
     end;
   end;

Types tableau et affectations

Des tableaux sont compatibles pour l'affectation uniquement s'ils ont le même type. Comme le langage Object Pascal utilise des équivalences de nom pour les types, le code suivant ne se compile pas.

 var
   Int1: array[1..10] of Integer;
   Int2: array[1..10] of Integer;
       ...
   Int1 := Int2;

Pour que l'affectation fonctionne, déclarez les variables comme suit :

 var Int1, Int2: array[1..10] of Integer;

ou :

 type IntArray = array[1..10] of Integer;
 var
    Int1: IntArray;
    Int2: IntArray;

Opérations de type chaîne supportées sur les tableaux dynamiques

Les tableaux dynamiques peuvent être manipulés comme les chaînes. Par exemple :

var
  A: array of integer;
  B: TBytes = [1,2,3,4]; //Initialization can be done from declaration
begin
  ...
  A:=[1,2,3]; // assignation using constant array
  A:=A+[4,5]; // addition - A will become [1,2,3,4,5]
  ...
end;

Routines dotées d'opérations de type chaîne

Certaines des routines intrinsèques de Object Pascal supportent les opérations sur les tableaux dynamiques en plus des opérations sur les chaînes.

La fonction Insert insère un tableau dynamique au début de l'index de position. Elle renvoie le tableau modifié :

  
var
  A: array of integer;
begin
  ...
  A:=[1,2,3,4];
  Insert(5,A,2); // A will become [1,2,5,3,4]
  ...
end;

La fonction Delete élimine des éléments d'un tableau dynamique et renvoie le tableau modifié :

  
var
  A: array of integer;
begin
  ...
  A:=[1,2,3,4];
  Delete(A,1,2); //A will become [1,4]
  ...
end;

La fonction Concat peut être utilisée pour concaténer deux tableaux dynamiques différents :

  
  A := Concat([1,2,3],[4,5,6]); //A will become [1,2,3,4,5,6]

Enregistrements (traditionnels)

Un enregistrement (analogue à une structure dans certains langages) représente un ensemble de données hétérogènes. Chaque élément est appelé un champ ; la déclaration d'un type enregistrement spécifie le nom et le type de chaque champ. Une déclaration de type enregistrement a la syntaxe suivante :

 type recordTypeName = record
   fieldList1: type1;
    ...
   fieldListn: typen;
 end

recordTypeName est un identificateur valide et où chaque type désigne un type, et chaque fieldList est un identificateur valide ou une liste d'identificateurs délimitée par des virgules. Le point-virgule final est facultatif.

Par exemple, la déclaration suivante crée un type enregistrement nommé TDateRec.

 type
   TDateRec = record
     Year: Integer;
     Month: (Jan, Feb, Mar, Apr, May, Jun,
             Jul, Aug, Sep, Oct, Nov, Dec);
     Day: 1..31;
   end;

Chaque TDateRec contient trois champs : une valeur entière appelée Year, une valeur d'un type énuméré appelée Month et une autre valeur entière comprise entre 1 et 31 appelée Day. Les identificateurs Year, Month et Day sont des désignateurs de champs pour TDateRec, et ils se comportent comme des variables. Néanmoins, la déclaration de type TDateRec n'alloue pas de mémoire pour les champs Year, Month et Day ; la mémoire est allouée quand vous instanciez l'enregistrement, de la manière suivante :

 var Record1, Record2: TDateRec;

Cette déclaration de variable crée deux instances de TDateRec, appelées Record1 et Record2.

Vous pouvez accéder aux champs d'un enregistrement en qualifiant les désignateurs de champs avec le nom de l'enregistrement :

 Record1.Year := 1904;
 Record1.Month := Jun;
 Record1.Day := 16;

Ou en utilisant une instruction with :

 with Record1 do
 begin
   Year := 1904;
   Month := Jun;
   Day := 16;
 end;

Vous pouvez alors copier les valeurs des champs de Record1 dans Record2 :

 Record2 := Record1;

Comme la portée d'un désignateur de champ est limitée à l'enregistrement dans lequel il apparaît, vous n'avez pas à vous préoccuper des conflits de noms entre les désignateurs de champs et les autres variables.

Au lieu de définir des types enregistrement, vous pouvez utiliser directement la construction record ... dans les déclarations de variables :

 var S: record
   Name: string;
   Age: Integer;
 end;

Cependant, une telle déclaration annule complètement les avantages des enregistrements, à savoir éviter le codage répétitif de groupes de variables identiques. De plus, des enregistrements déclarés séparément avec cette méthode ne sont pas compatibles pour l'affectation, même si leur structure est identique.

Parties variant dans les enregistrements

Un type enregistrement peut avoir une partie variant, qui ressemble à une instruction case. La partie variant doit venir après les autres champs de la déclaration de l'enregistrement.

Pour déclarer un type enregistrement avec une partie variant, utilisez la syntaxe suivante :

 type recordTypeName = record
   fieldList1: type1;
    ...
   fieldListn: typen;
 case tag: ordinalType of
   constantList1: (variant1);
    ...
   constantListn: (variantn);
 end;

La première partie de la déclaration, jusqu'au mot réservé case, est identique à celle d'un type enregistrement standard. Le reste de la déclaration, du case jusqu'au point-virgule final facultatif, est appelé la partie variant. Dans la partie variant :

  • tag est facultatif, ce peut être tout identificateur valide. Si vous omettez tag, omettez également le caractère deux-points (:) après.
  • ordinalType désigne un type ordinal.
  • Chaque constantList est une constante désignant une valeur du type ordinalType, ou une liste de telles constantes délimitée par des virgules. Une valeur ne doit pas apparaître plus d'une fois dans tous les constantLists.
  • Chaque variant est une liste, délimitée par des virgules, de déclarations ressemblant aux constructions fieldList: type de la partie principale du type enregistrement. Donc un variant est de la forme :
 fieldList1: type1;
   ...
 fieldListn: typen;

où chaque fieldList est un identificateur valide ou une liste d'identificateurs délimitée par des virgules, chaque type désigne un type et le point-virgule final est facultatif. Les types ne doivent pas être des chaînes longues, des tableaux dynamiques, des variants (c'est-à-dire des types Variant), des interfaces ou des types structurés contenant ces mêmes types. Par contre, ce peut être des pointeurs sur ces types.

Les enregistrements ayant des parties variant ont une syntaxe complexe mais une sémantique très simple. La partie variant d'un enregistrement contient plusieurs variants qui partagent le même espace mémoire. Vous pouvez lire ou écrire dans chaque champ de tout variant à n'importe quel moment ; mais si vous écrivez dans un champ d'un variant puis dans un champ d'un autre variant, vous risquez d'écraser vos propres données. Le sélecteur (tag), s'il est spécifié, fonctionne comme un champ supplémentaire (de type ordinalType) dans la partie non variant de l'enregistrement.

Les parties variant ont deux rôles. Tout d'abord, supposons que vous voulez créer un type enregistrement ayant des champs pour différentes sortes de données, tout en sachant que vous n'aurez jamais besoin d'utiliser tous les champs d'une instance d'enregistrement unique. Par exemple :

 type
   TEmployee = record
   FirstName, LastName: string[40];
   BirthDate: TDate;
   case Salaried: Boolean of
     True: (AnnualSalary: Currency);
     False: (HourlyWage: Currency);
 end;

L'idée ici est que chaque employé a soit un salaire soit un taux horaire, mais pas les deux. Donc, quand vous créez une instance de TEmployee, il n'y a pas de raison pour allouer de la mémoire pour les deux champs. Dans ce cas, la seule différence entre les variants est le nom des champs, mais les champs peuvent être de types différents. Voici des exemples plus compliqués :

 type
   TPerson = record
   FirstName, LastName: string[40];
   BirthDate: TDate;
   case Citizen: Boolean of
     True: (Birthplace: string[40]);
     False: (Country: string[20];
             EntryPort: string[20];
             EntryDate, ExitDate: TDate);
   end;
 
 type
   TShapeList = (Rectangle, Triangle, Circle, Ellipse, Other);
   TFigure = record
     case TShapeList of
       Rectangle: (Height, Width: Real);
       Triangle: (Side1, Side2, Angle: Real);
       Circle: (Radius: Real);
       Ellipse, Other: ();
   end;

Pour chaque instance d'enregistrement, le compilateur alloue assez de mémoire pour contenir tous les champs du variant le plus volumineux. Le sélecteur (tag) facultatif et les constantLists (comme Rectangle, Triangle, et ainsi de suite dans le dernier exemple) ne jouent aucun rôle dans la manière dont le compilateur gère les champs ; ils ne sont là que comme commodité pour le programmeur.

La seconde raison d'utiliser des parties variant, c'est qu'elles vous permettent de traiter les mêmes données comme si elles étaient de différents types, et ce même dans les cas où le compilateur n'autorise pas un transtypage. Par exemple, si vous avez un Real sur 64 bits comme premier champ dans un variant et un Integer sur 32 bits comme premier champ d'un autre variant, vous pouvez assigner une valeur au champ Real puis en lire les 32 premiers bits comme valeur du champ Integer (et par exemple les transmettre à une fonction nécessitant des paramètres integer).

Enregistrements (avancés)

En plus des types enregistrement traditionnels, le langage Object Pascal autorise des types enregistrement plus complexes, similaires à des classes. En plus des champs, les enregistrements peuvent avoir des propriétés et des méthodes (incluant les constructeurs), des propriétés de classe, des méthodes de classe, des champs de classe et des types imbriqués. Pour de plus amples informations sur ces sujets, voir Classes et objets dans la documentation. Voici un exemple de définition de type enregistrement avec une fonctionnalité de type classe.

 type
   TMyRecord = record
     type
       TInnerColorType = Integer;
     var
       Red: Integer;
     class var
       Blue: Integer;
     procedure printRed();
     constructor Create(val: Integer);
     property RedProperty: TInnerColorType read Red write Red;
     class property BlueProp: TInnerColorType read Blue write Blue;
 end;
 
 constructor TMyRecord.Create(val: Integer);
 begin
   Red := val;
 end;
 
 procedure TMyRecord.printRed;
 begin
   Writeln('Red: ', Red);
 end;

Bien que les enregistrements puissent maintenant partager l'essentiel de la fonctionnalité des classes, il existe certaines différences importantes entre les classes et les enregistrements.

  • Les enregistrements ne prennent pas en charge l'héritage.
  • Les enregistrements peuvent contenir une partie variant alors que les classes ne le peuvent pas.
  • Les enregistrements sont des types valeur, copiés par affectation, transmis par valeur, et alloués sur la pile à moins qu'ils ne soient déclarés globalement ou alloués explicitement au moyen des fonctions New et Dispose. Les classes sont des types référence ; elles ne sont pas copiées par affectation, elles sont transmises par référence et sont allouées sur le tas.
  • Les enregistrements permettent la surcharge des opérateurs sur la plate-forme Win32 . Toutefois les classes ne permettent pas la surcharge des opérateurs.
  • Les enregistrements sont construits automatiquement, en utilisant un constructeur par défaut sans argument, alors que les classes doivent être construites explicitement. Comme les enregistrements ont un constructeur par défaut sans argument, tous les constructeurs d'enregistrement définis par l'utilisateur doivent avoir un ou plusieurs paramètres.
  • Les types enregistrement ne peuvent pas avoir de destructeurs.
  • Les méthodes virtuelles (celles spécifiées par les mots-clés virtual, dynamic et message) ne peuvent pas être utilisées dans les types enregistrement.
  • A l'inverse des classes, les types enregistrement de la plate-forme Win32 ne peuvent pas implémenter les interfaces.

Types fichiers (Win32)

Les types fichiers, comme disponibles sur la plate-forme Win32, sont des séquences d'éléments du même type. Les routines standard d'Entrées/Sorties utilisent le type prédéfini TextFile ou Text, qui représente un fichier contenant des caractères organisés en lignes. Pour de plus amples informations sur les entrées et sorties de fichiers, voir Routines standard et entrées-sorties sous la section "Entrées et sorties de fichiers".

Pour déclarer un type fichier, utilisez la syntaxe :

type fileTypeName = file of type

fileTypeName est un identificateur valide et "type" un type de taille fixe. Les types pointeur, implicites ou explicites ne sont pas permis. Un fichier ne peut donc pas contenir des tableaux dynamiques, des chaînes longues, des classes, des objets, des pointeurs, des variants, d'autres fichiers ou des types structurés en contenant.

Par exemple :

 type
    PhoneEntry = record
      FirstName, LastName: string[20];
      PhoneNumber: string[15];
      Listed: Boolean;
    end;
    PhoneList = file of PhoneEntry;

déclare un type fichier pour enregistrer des noms et des numéros de téléphone.

Vous pouvez également utiliser directement la construction file of ... dans une déclaration de variable. Par exemple,

 var List1: file of PhoneEntry;

Le mot file seul indique un fichier sans type :

 var DataFile: file;

Pour de plus amples informations, voir "Fichiers non typés" dans Routines standard et entrées-sorties.

Les fichiers ne sont pas autorisés dans les tableaux ou les enregistrements.

Voir aussi

Exemples de code