2017-09-20 2 views
3

Je voulais faire une référence variable de son propre contenu si je l'ai fait:Faire référence à une variable de son propre contenu de la chaîne

$x=\$x;

mais cela ne fonctionne pas comme je m'y attendais, $x est devenu une référence à elle-même si $$x est la même que $x. Ce que je m'attendais à ce que $$x devienne la chaîne d'origine. Pourquoi est-ce et comment dois-je l'écrire correctement sans faire une copie de la chaîne dans $x? Parce que dans certains cas $x peut être une énorme chaîne.

+3

Même si vous pouviez faire ce que vous essayiez de faire, le contenu original serait parti à cause du comptage des références. Utilisez simplement une variable différente pour la référence. – AKHolland

+0

@AKHolland oh, c'est vrai ... Je ne pensais pas à la référence de comptage ... – soger

+1

@AKHolland, Nonsense. Il ne peut pas être parti s'il est toujours accessible. Si l'OP pouvait faire ce qu'il essayait de faire (accéder à la valeur d'origine en tant que '$$ x'), alors ce serait un bug majeur dans Perl si son compte de référence avait atteint zéro. – ikegami

Répondre

3

Ce que vous demandez est impossible. Une variable ne peut pas contenir à la fois une référence et une chaîne. Vous devez utiliser deux variables. Cela vous laisse avec deux options.

stocker la référence dans une nouvelle variable

$ perl -e' 
    use feature qw(say); 
    my $x = "abc"; 
    my $y = \$x; 
    say $y; 
    say $$y; 
' 
SCALAR(0x232a398) 
abc 

Nice et simple, efficace, et pas de confusion quant à ce que la variable contient à quel moment. L'inconvénient de cette approche est que les références à $x d'origine ne verront pas la modification. Il est difficile d'imaginer une situation où cela aurait de l'importance, cependant.

Notez que la nouvelle var pourrait même avoir le même nom que l'ancienne. Je ne recommande pas cela car il est inutilement confus et sujet aux erreurs.

$ perl -e' 
    use feature qw(say); 
    my $x = "abc"; 
    my $x = \$x; 
    say $x; 
    say $$x; 
' 
SCALAR(0x232a398) 
abc 

stocker la valeur dans une nouvelle variable

$ perl -e' 
    use feature qw(say); 
    my $x = "abc"; 
    $x = \(my $container = $x); 
    say $x; 
    say $$x; 
' 
SCALAR(0x175cbe0) 
abc 

L'inconvénient de cette approche est qu'elle consiste à copier la chaîne. Cependant, c'est seulement le cas jusqu'à 5.20. 5.20 a introduit un mécanisme de copie sur écriture pour les chaînes. Cela signifie que ce qui précède ne copiera pas la chaîne dans 5.20+; il va juste copier un pointeur à la place. Notez que les deux scalaires partagent le même tampon de chaîne (0x2ac53d0) dans l'exemple suivant:

$ perl -MDevel::Peek -e'my $x = "abc"; my $y = $x; Dump($_) for $x, $y;' 2>&1 \ 
    | grep -P '^(?:SV| FLAGS| PV)\b' 
SV = PV(0x2a9f0c0) at 0x2abcdc8 
    FLAGS = (POK,IsCOW,pPOK) 
    PV = 0x2ac53d0 "abc"\0 
SV = PV(0x2a9f150) at 0x2abcde0 
    FLAGS = (POK,IsCOW,pPOK) 
    PV = 0x2ac53d0 "abc"\0 

Alors que $x = \"$x" a été suggéré comme une version plus courte de $x = \(my $container = $x);, elle force mise en chaîne, et il copie l'intégralité de la chaîne, même dans les versions de Perl qui prend en charge COW.

1

Attribuer une référence à la valeur, et non à la variable:

my $string = 'abcefgh'; 
$string = \ "$string"; 

print $$string, "\n"; 
+0

Mais cela ne ferait-il pas une copie de la chaîne? Est-ce que "abcefgh" et "$ string" n'existeraient pas en même temps? – soger

+0

@soger: Alors créez le au début: 'my $ string = \ 'abcdefgh';'. – choroba

+1

la vraie vie n'est pas si simple. – soger