Pourquoi la programmation Perl utilise-t-elle local (pas mon) pour les descripteurs de fichiers?

StackOverflow https://stackoverflow.com/questions/613906

  •  03-07-2019
  •  | 
  •  

Question

Lorsque je lis Programmation Perl , 2e édition, page 51, quelque chose me déroute:

sub newopen {
    my $path = shift;
    local *FH;    #not my!
    open (FH, $path) || return undef;
    return *FH;
}

$fh = newopen('/etc/passwd');

Mon je sais, pourquoi on ne nous recommande pas d’utiliser mon? Jusqu'ici, je ne vois pas que tout ira mal si nous utilisons my ().

Merci!

Était-ce utile?

La solution

La réponse banale est que vous devez utiliser local car my * FH est une erreur de syntaxe.

Le " right " (mais pas très éclairant) la réponse est que vous le faites mal. Vous devriez utiliser des descripteurs de fichiers lexicaux et la forme à trois arguments de open .

sub newopen {
    my $path = shift;
    my $fh;
    open($fh, '<', $path) or do {
        warn "Can't read file '$path' [$!]\n";
        return;
    }
    return $fh;
}

Pour vraiment répondre à pourquoi nécessite une explication de la différence entre les variables lexicales et globales et entre la portée et la durée d'une variable.

La portée d'une variable est la partie du programme où son nom est valide. La portée est une propriété statique. La durée d'une variable, en revanche, est une propriété dynamique. La durée est le temps pendant l'exécution d'un programme que la variable existe et contient une valeur.

my déclare une variable lexicale. Les variables lexicales ont une portée allant du point de déclaration à la fin du bloc (ou fichier) englobant. Vous pouvez avoir d'autres variables du même nom dans différentes portées sans conflit. (Vous pouvez également réutiliser un nom dans des portées qui se chevauchent, mais ne le faites pas.) La durée des variables lexicales est gérée par le comptage des références. Tant qu'il existe au moins une référence à une variable, la valeur existe, même si le nom n'est pas valide dans une portée particulière! my a également un effet d’exécution - il attribue une nouvelle variable portant le nom donné.

local est un peu différent. Il fonctionne sur des variables globales. Les variables globales ont une portée globale (le nom est valable partout) et une durée de la vie entière du programme. Ce que local fait, c'est de modifier temporairement la valeur d'une variable globale. Ceci est parfois appelé "cadrage dynamique". La modification commence au point de la déclaration local et persiste jusqu'à la fin du bloc englobant, après quoi l'ancienne valeur est restaurée. Il est important de noter que la nouvelle valeur n'est pas limitée au bloc - elle est visible partout (y compris les sous-routines appelées). Les règles de comptage des références s'appliquent toujours. Vous pouvez donc conserver et conserver une référence à une valeur localisée une fois la modification expirée.

Retour à l'exemple: * FH est une variable globale. Plus précisément, il s'agit d'un "typeglob". - un conteneur pour un ensemble de variables globales. Un typeglob contient un emplacement pour chacun des types de variables de base (scalar, array, hash) et quelques autres choses. Historiquement, Perl utilisait des typesglobs pour stocker les descripteurs de fichiers et leur local pour les aider à s'assurer qu'ils ne s'embrouillaient pas les uns les autres. Les variables lexicales n’ont pas de typeglobs, c’est pourquoi dire my * FH est une erreur de syntaxe.

Dans les versions modernes de Perl, les variables lexicales peuvent et doivent être utilisées comme descripteurs de fichiers. Et cela nous ramène à la " right " répondre.

Autres conseils

Dans votre exemple de code, l'appel de la sous-routine intégrée open utilise un mot nu comme descripteur de fichier, qui est l'équivalent d'une variable globale. Comme la réponse de Nathan Fellman a été expliquée à l'aide de . local localisera ce mot nu dans le bloc de code actuel, au cas où une autre variable globale du même nom serait définie ailleurs dans le script ou le module. Cela évitera que la nouvelle déclaration supprime la variable globale définie précédemment.

C’était une pratique très courante à l’époque Perl, mais à partir de Perl 5.6, il est de loin préférable d’utiliser un scalaire (avec la déclaration my à laquelle vous avez fait allusion dans votre question). ) pour définir votre descripteur de fichier et utiliser en plus l'appel à trois arguments pour open .

use Carp;
open my $error_log, '>>', 'error.log' or croak "Can't open error.log: $OS_ERROR";

En passant, veuillez noter que pour la lecture et l'écriture standard d'entrées / sorties, il est toujours préférable d'utiliser les deux arguments open :

use Carp;
open my $stdin, '<-' or croak "Can't open stdin: $OS_ERROR";

Vous pouvez également utiliser le IO :: Fichier module pour bénir le descripteur de fichier à la classe:

use IO::File;
my $error_log = IO::File->new('error.log', '>>') or croak "Can't open error.log: $OS_ERROR");

La majorité du crédit va ici à Damian Conway, auteur de l'excellent livre Perl Best Practices . Si vous êtes sérieux au sujet du développement de Perl, vous vous devez d’acheter ce livre.

Pourquoi lisez-vous un livre obsolète? La 3ème édition est sortie depuis longtemps! Quelle version de Perl utilisez-vous? La 2e édition décrit Perl 5.004 (5.4.x) ou à peu près.

Ces jours-ci, vous ne devriez pas utiliser la notation typeglob pour les descripteurs de fichiers; utiliser les 'descripteurs de fichier lexicaux' (voir ouvert , je pense) ou le FileHandle , ou l'un de ses parents à la place.

Merci à Michael Schwern et à Ysth pour les commentaires intégrés ici.

Je pense que c'est parce que my alloue une nouvelle copie de la variable sur la pile et est perdue lorsque vous quittez le bloc. local enregistre le * FH existant ailleurs et remplace le * FH existant. Il restaure l'ancien lorsque vous quittez la pile. Avec my , le typeglob * FH sort du cadre lorsque vous quittez le bloc. Avec local , il continue d'exister, vous pouvez donc continuer à l'utiliser après le retour.

Je ne suis pas sûr à 100% de cela, mais peut-être que cela peut vous orienter dans la bonne direction.

Voir les descripteurs de fichiers localisés ici , je suppose que cela explique tout.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top