Vă mulțumim pentru susținere

Puteți forța fie un reflex scalar sau matrice să fie o matrice în Perl?

Am o variabilă perl $ results care este returnată de la un serviciu. Valoarea ar trebui să fie o matrice și $ results ar trebui să fie o referință de matrice. Cu toate acestea, atunci când matricea are un singur element în ea, $ results va fi setat la acea valoare și nu o matrice de referință care conține acel element.

Vreau să fac o buclă foreach pe matricea așteptată. Fără a verifica ref ($ results) eq 'ARRAY' , există vreo modalitate de a avea ceva echivalent cu următoarele:

foreach my $result (@$results) {
    # Process $result
}

Acest eșantion de cod special va funcționa pentru referință, dar se va plânge pentru scalarul simplu.

EDIT: Ar trebui să clarific faptul că nu există nicio modalitate de a schimba ceea ce este returnat din serviciu. Problema este că valoarea va fi scalară atunci când există o singură valoare și va fi o referință de matrice atunci când există mai mult de o valoare.

0
adăugat editat
Acest comportament mă face să vreau să strig și să fiu, "STOPID PERL!" Dar apoi îmi dau seama că limbile care nu necesită acest nonsens încă o fac sub capota, ceea ce mă face să mă deranjeze puțin mai puțin ....
adăugat autor Rooster

5 răspunsuri

Tocmai am testat acest lucru cu:

  #! / usr / bin / perl -w
utilizați stricte;

sub testit {

 my @ret = ();
 dacă (trecerea) {
   împinge @ ret, 1;
   împinge @ ret, 2;
   împinge @ ret, 3;
} Else {
  împingeți @ret, "singură";
}

returnați @ @ ret;
}

(@ {testit (1)}) {
  print $ r "test1 \ n";
}
(@ {testit ()}) {
   print $ r "test2 \ n";
}
 

Și se pare că funcționează bine, deci mă gândesc că are ceva de-a face cu rezultatul obținut de la serviciu? Dacă nu aveți niciun control asupra serviciului de întoarcere, este posibil să fie greu să cedați

0
adăugat

nu sunt sigur că există altă cale decât:

 $ rezultat = [$ rezultat] dacă ref ($ rezultat) ne 'ARRAY';
pentru fiecare .....
 
0
adăugat

Dacă nu puteți să ...

for my $result ( ref $results eq 'ARRAY' ? @$results : $results ) {
    # Process result
}

sau asta...

for my $result ( ! ref $results ? $results : @$results ) {
    # Process result
}

atunci ar fi posibil să încercați ceva înspăimântător ca acest lucru!

for my $result ( eval { @$results }, eval $results ) {
    # Process result
}

și pentru a evita acest șir periculos eval devine foarte urât fugly! ....

for my $result ( eval { $results->[0] } || $results, eval { @$results[1 .. $#{ $results }] } ) {
    # Process result
}

PS. Preferința mea ar fi să o abstracționez în sub ala call_to_service () exemplu dat de reatmon.

0
adăugat
Nu e un eval de șir. Iar looping (o expresie care implică rezultate $) este foarte diferită de looping over (@ $ results). Primul va copia matricea (memorie consumatoare); acesta din urmă îi va alias (și va permite modificarea elementelor prin intermediul variabilei buclă).
adăugat autor ysth
@ysth - Există ... vedeți "rezultate eval $". Sugestia mea a fost să folosesc exemplul call_to_service () dat mai devreme. Răspunsul meu a fost un pic de "limbă în soluția obrazului" față de restricția impusă de poster, deci da binele lui să-i sublinieze defectele.
adăugat autor draegtun

Aș re-factor cod în bucla și apoi face

if( ref $results eq 'ARRAY' ){
    my_sub($result) for my $result (@$results);
}else{
    my_sub($results);
}

Sigur că aș face asta doar dacă codul din buclă nu era banal.

0
adăugat

O altă soluție ar fi să înfășurați apelul către server și să îl întoarceți întotdeauna o matrice pentru a simplifica restul vieții:

sub call_to_service
{
    my $returnValue = service::call();

    if (ref($returnValue) eq "ARRAY")
    {
        return($returnValue);
    }
    else
    {
       return( [$returnValue] );
    }
}

Apoi, puteți ști mereu că veți primi o referință la o matrice, chiar dacă ar fi un singur element.

foreach my $item (@{call_to_service()})
{
  ...
}
0
adăugat