Qu'arrive-t-il à une regex sans correspondance dans un appel de sous-programme Perl?

J'essaie de donner un sens à ce qui se passe avec une regex non-correspondante dans un appel de sous-programme. Considérez ce script:

sub routine{
    print Dumper(\@_);
}

my $s = 'abc123';

# These pass a single element to &routine
&routine( $s =~ /c/ );      # 1. passes (1)
&routine(2 == 3);           # 2. passes ('')
&routine(3 == 3);           # 3. passes (1)

# The following two calls appear to be identical 
&routine( $s =~ /foobar/ ); # 4. passes ()
&routine();                 # 5. passes ()

In the above script, numbers 1, 2 and 3 all pass a single value to &routine. I'm surprised that number 4 doesn't pass a false value, but rather passes nothing at all!

Il ne semble pas possible que la regex non-correspondante n'évalue rien du tout, puisque le même type de signature dans un conditionnel n'est pas valide:

# This is fine
if( $s =~ /foobar/ ){
   print "it's true!\n";
}

# This is a syntax error
if( ){
   print "Hmm...\n"; # :/
}

What happens to the non-matching regex when it's used in a subroutine call? Further, is it possible for &routine to figure out whether or not it's been called with a non-matching regex, vs nothing at all?

0

1 Réponses

Lorsque l'opérateur de correspondance = ~ est utilisé dans la liste contexte renvoie une liste de correspondances. Lorsqu'il n'y a pas de correspondance, cette liste est vide (appelée aussi liste vide), et la liste vide est passée à votre sous-routine routine qui, à son tour, fait que @_ est vide .

Si vous voulez explicitement passer la valeur false de "Est-ce que cette expression a renvoyé des correspondances?" vous devez effectuer votre match dans un contexte scalaire. Vous pouvez le faire en utilisant le mot-clé scalar

&routine( scalar $s =~ /foobar/ );

qui transmettra la valeur '' (false) à votre sous-programme routine . Appeler un sub sans aucun argument passe effectivement cette liste vide, ainsi votre dernier exemple serait écrit correctement:

if (() ) {
   print "Hmm...\n";
}

ce qui n'est pas une erreur de syntaxe car en Perl 0 , '' , et () tous représentent false.

0
ajouté
Qu'en est-il de cette dernière question? Un sous-programme peut-il savoir comment il a été appelé (c'est-à-dire avec rien ou avec une liste vide)?
ajouté l'auteur ajwood, source
@Borodin Je veux écrire un sous-code bool qui peut rendre la valeur d'un booléen plus prévisible.
ajouté l'auteur ajwood, source
@Borodin Par exemple, dans cette question , une vraie valeur de retour peut parfois être une, et d'autres fois être un entier plus grand. Je suis dans une situation où je voudrais que mes valeurs de vérité soient prévisibles.
ajouté l'auteur ajwood, source
@HunterMcMillen C'est exactement ce que j'ai :) J'ai tendance à aimer écrire des sous-titres qui vérifient leurs arguments pour la santé mentale; dans ce cas, j'aimerais que le sous-marin meure s'il n'a pas reçu exactement un argument. Mais on dirait que je vais faire une exception dans ce cas :)
ajouté l'auteur ajwood, source
@Borodin Votre évaluation de ma situation est exacte, merci :)
ajouté l'auteur ajwood, source
Les arguments @ajwood des sous-programmes sont évalués avant d'être transmis au sous-programme. Il n'y a donc pas de différence entre appeler un sous avec une expression qui aboutit à la liste vide ou l'appeler sans argument du tout. Je ne crois pas que cela puisse être détecté.
ajouté l'auteur Hunter McMillen, source
@ajwood sub bool {mon $ truthiness = shift; retour $ vérité? dix; }
ajouté l'auteur Hunter McMillen, source
@Borodin Que diriez-vous de sub bool {my $ truthiness = shift; retour $ vérité? 1: (wantarray? (): 0); } :)
ajouté l'auteur Hunter McMillen, source
@Borodin point juste, c'est beaucoup plus facile à comprendre aussi
ajouté l'auteur Hunter McMillen, source
@ajwood: non, un sous-programme ne peut pas distinguer s'il a été appelé sans paramètres ou une expression créant une liste vide.
ajouté l'auteur ysth, source
@ajwood: Pourquoi voudriez-vous que votre sous-programme soit conscient de la source de ses arguments? Si vous devez savoir que le paramètre est le résultat d'une correspondance regex, passez un second paramètre pour le dire
ajouté l'auteur Borodin, source
@ajwood: Le problème est que, disons, une chaîne vide "" dans le contexte de la liste est vrai. Un return pur gère cela en retournant une liste vide dans la liste conttext, et undef dans un contexte scalaire, donc c'est toujours false . Je pense que vous êtes en train de combler un trou qui n'existe pas, et probablement parce que vous êtes plus familier avec un langage qui gère les valeurs booléennes différemment
ajouté l'auteur Borodin, source
@HunterMcMillen: Le problème avec ça c'est que if (mon @x = bool (0)) va réussir
ajouté l'auteur Borodin, source
@ajwood: Vous pouvez passer une valeur scalaire vraie/fausse avec la routine (scalaire $ s = ~/foobar /) mais je pense vraiment que vous essayez de programmer dans une langue différente. Soit dit en passant, ne pas appeler les sous-routines avec une esperluette & . Cela n'a pas été une pratique correcte depuis plus de vingt ans
ajouté l'auteur Borodin, source
@HunterMcMillen: Un simple retour est déjà sensible au contexte, donc vous pouvez écrire sub bool {shift? return 1: return}
ajouté l'auteur Borodin, source