2010-10-10 5 views
16

Perl hat einen conditional Operator, der ein C's conditional operator ist.Sollte ich Perl bedingten verwenden? : operator als switch/case statement oder anstelle von elsif?

zu aktualisieren, der bedingten Operator in C und in Perl ist:

(test) ? (if test was true) : (if test was false) 

und wenn sie mit einem L-Wert verwendet, können Sie zuweisen und Test mit einer Aktion:

my $x= $n==0 ? "n is 0" : "n is not 0"; 

Ich lese Igor Ostrovskys Blog auf A neat way to express multi-clause if statements in C-based languages und erkannte, dass dies auch in Perl ein "ordentlicher Weg" ist.

Zum Beispiel: (edit: verwendete Jonathan Leffler lesbare Form ...)

# ternary conditional form of if/elsif construct: 
my $s= 
     $n == 0  ? "$n ain't squawt" 
    : $n == 1  ? "$n is not a lot" 
    : $n < 100 ? "$n is more than 1..." 
    : $n < 1000 ? "$n is in triple digits" 
    :    "Wow! $n is thousands!" ; #default 

die viel einfacher als das, was viele schreiben würde in Perl liest: (edit: verwendet cjm die elegantere my $t=do{ if }; Form in rafis Antwort)

# Perl form, not using Switch or given/when 
my $t = do { 
    if ($n == 0) { "$n ain't squawt"  } 
    elsif ($n == 1) { "$n is not a lot"  } 
    elsif ($n < 100) { "$n is more than 1..." } 
    elsif ($n < 1000) { "$n is in triple digits" } 
    else    { "Wow! $n is thousands!" } 
}; 

Gibt es irgendwelche Probleme oder Nachteile hier? Warum würde ich auf diese Weise kein erweitertes bedingtes Formular schreiben, anstatt if(something) { this } elsif(something) { that } zu verwenden?

Der bedingte Operator hat right associativity and low precedence. Also:

a ? b : c ? d : e ? f : g 

wird interpretiert als:

a ? b : (c ? d : (e ? f : g)) 

Ich nehme an, Sie Klammer benötigen, wenn Sie Ihre Tests als ?: einer der wenigen Betreiber niedrigere Priorität verwendet. Sie könnten auch Blöcke in das Formular mit Klammern setzen, denke ich.

Ich weiß über die veralteten use Switch oder über given/when Konstrukte Perl 5.10, und ich bin nicht auf der Suche für einen Vorschlag, diese zu nutzen.

Das sind meine Fragen:

  • Sie diese Syntax in Perl verwendet gesehen ** habe ich nicht, und es ist nicht in perlop oder perlsyn als Alternative zu wechseln.

  • Gibt es potentielle Syntaxprobleme oder "Gotchas" mit einem Bedingungs-/Ternäroperator auf diese Weise?

  • Meinung: Ist es für Sie besser verständlich? Entspricht es Idiomatic Perl?

-------- Bearbeiten -

Ich nahm Jonathan Leffler Antwort, weil er mich zu Perl Best Practices hingewiesen. Der relevante Abschnitt ist 6.17 auf Tabular Ternaries. Dies erlaubte mir, den Gebrauch weiter zu untersuchen. (Wenn Sie Google Perl Tabular Ternaries besuchen, können Sie weitere Kommentare sehen.)

Conways zwei Beispiele sind:

my $salute; 
if ($name eq $EMPTY_STR) { 
    $salute = 'Dear Customer'; 
} 
elsif ($name =~ m/\A ((?:Sir|Dame) \s+ \S+)/xms) { 
    $salute = "Dear $1"; 
} 

elsif ($name =~ m/([^\n]*), \s+ Ph[.]?D \z/xms) { 
    $sa1ute = "Dear Dr $1"; 
} 
else { 
    $salute = "Dear $name"; 
} 

VS:

  # Name format...       # Salutation... 
my $salute = $name eq $EMPTY_STR      ? 'Dear Customer' 
      : $name =~ m/ \A((?:Sir|Dame) \s+ \S+) /xms ? "Dear $1" 
      : $name =~ m/ (.*), \s+ Ph[.]?D \z  /xms ? "Dear Dr $1" 
      :            "Dear $name" 
      ; 

Meine Schlussfolgerungen sind:

  • Conways ?: Beispiel besser lesbar und einfacher zu mir ist, als die if/elsif Form, aber ich konnte sehen, wie die Form schwer zu verstehen sein könnte.

  • Wenn Sie 5.13.1 haben Perl, verwenden my $t=do { given { when } }; als Aufgabe als rafi has done. denke ich given/when die beste Idiom jetzt ist, es sei denn, die tabellarische ternären Format besser für Ihren speziellen Fall ist.

  • Wenn Sie Perl 5.10+ haben, verwenden Sie given/when im Allgemeinen anstelle von Switch oder wenn Sie irgendeine Art von Falltyp-Schalter benötigen.

  • Ältere Perls, dies ist eine feine Form für einfache Alternativen oder als Alternative zu einer Fallanweisung. Es ist besser als Switch ich denke.

  • Die Assoziativität von rechts nach links bedeutet, dass das Formular von unten nach oben ausgewertet wird. Denken Sie daran, dass bei der Verwendung ...

Antwort

15

Das Layout für den bedingten Operator gezeigt schwer zu lesen. Das ist mehr wie das, was ich mich erinnere Perl Best Practices Empfehlung:

my $s = $n == 0 ? "$n ain't squawt" 
     : $n == 1 ? "$n is not a lot" 
     : $n < 100 ? "$n is more than 1..." 
     : $n < 1000 ? "$n is in triple digits" 
     :    "Wow! $n is thousands!"; # default... 

Und es gibt Zeiten, in denen es besser ist, eine kompaktere Notation mit der if Notation zu verwenden, auch:

if ($n == 0) { $t = "$n ain't squawt";  } 
    elsif ($n == 1) { $t = "$n is not a lot";  } 
    elsif ($n < 100) { $t = "$n is more than 1..."; } 
    elsif ($n < 1000) { $t = "$n is in triple digits"; } 
    else    { $t = "Wow! $n is thousands!" ; } 

Beide reformattings betonen die Ähnlichkeit der verschiedenen Abschnitte des Codes, die das Lesen und Verstehen erleichtern.

+0

Ich mag Ihre Formatierung für beide Alternativen besser, und die bedingte Form, die Sie immer noch leichter zu lesen als die if/elsif. Was denken Sie? – dawg

+0

@drewk: Sie sind beide ziemlich lesbar; Das bedingte Operatorformular hat eine einzige Zuweisung, so dass klar ist, dass ein einzelner Wert zugewiesen wird, während bei der if-chain-Version eine der Aktionen "$ l =" something ";" und der Tippfehler im Variablennamen sein könnte könnte für eine Weile unpunktiert bleiben. Also, ja, ich denke, es gibt Vorteile für den bedingten Operator - aber es ist keine schrecklich starke Präferenz. –

19

Ich habe dieses Idiom in Perl verwendet. Da der Ternäroperator ? : ein Bediener ist, ist er in perlop, nicht perlsyn dokumentiert.

In meinen Augen ist es eine Art idiomatische Perl, aber der Hauptzweck dieser in Perl scheint das Fehlen einer richtigen switch Anweisung zu vermeiden, während nicht riesige if/else -Kaskaden schreiben. Dies wurde jedoch vor Jahren in Perl 5.10.0 behoben. In diesen Tagen kann ich nicht viele Gründe, sehen Sie nicht die oben, da dies zu schreiben, die weit besser lesbar als (ab) unter Verwendung des ternären zu sein scheint:

given ($n) { 
    when (0)   { $t = "$_ ain't squawt"  } 
    when (1)   { $t = "$_ is not a lot"  } 
    when ($_ < 100) { $t = "$_ is more than 1..." } 
    when ($_ < 1000) { $t = "$_ is in triple digits" } 
    default   { $t = "Wow! $_ is thousands!" } 
} 

oder, wie von Perl 5.13.1, auch als :

my $t = do { 
    given ($n) { 
     when (0)   { "$_ ain't squawt"  } 
     when (1)   { "$_ is not a lot"  } 
     when ($_ < 100) { "$_ is more than 1..." } 
     when ($_ < 1000) { "$_ is in triple digits" } 
     default   { "Wow! $_ is thousands!" } 
    } 
}; 

Eine weitere Alternative etwas so sein würde, arbeitet davon auf allen perl-Versionen:

my @cases = (
    [sub { $_ == 0 }, sub { "$_ ain't squawt"  }], 
    [sub { $_ == 1 }, sub { "$_ is not a lot"  }], 
    [sub { $_ < 100 }, sub { "$_ is more than 1..." }], 
    [sub { $_ < 1000 }, sub { "$_ is in triple digits" }], 
    [sub { 1 },   sub { "Wow! $_ is thousands!" }], 
); 

for my $case (@cases) { 
    local $_ = $n; 
    next unless $case->[0]->(); 
    $t = $case->[1]->(); 
    last; 
} 

Während diese beiden großen if/elsif/else -cascades mit vermeidet, und muss nicht Features von r ecent perls, ist es wahrscheinlich nicht die Mühe für dieses einfache Beispiel wert. Ich kann jedoch sehr gut sehen, dass ein Ansatz wie dieser mit vielen Bedingungen und dem Zwang, alte Perls zu unterstützen, nützlich ist.

(Beachten Sie auch, dass Ihr erstes Beispiel nicht behandelt, ob $ n kleiner als Null ist oder überhaupt keine Zahl ist.

)

Hinweis von cjm: Sie können auch in allen Versionen von Perl tun dies 5:

my $t = do { 
    if ($n == 0) { "$n ain't squawt"  } 
    elsif ($n == 1) { "$n is not a lot"  } 
    elsif ($n < 100) { "$n is more than 1..." } 
    elsif ($n < 1000) { "$n is in triple digits" } 
    else    { "Wow! $n is thousands!" } 
}; 
+0

Sie konnten immer den Rückgabewert von 'if' in einem' do' -Block verwenden. Ich habe ein Beispiel hinzugefügt. Es ist nur "gegeben" in 5.10 und 5.12, was das nicht erlaubt. – cjm

+0

Guter Punkt. Vielen Dank! :-) – rafl

+1

Es ist nicht * der * ternäre Operator, es ist * ein * ternärer Operator. Es ist * der * bedingte Operator. – Ether

5

ich die gekettet gesehen habe Conditionals ziemlich, benutzt es manchmal und hasste es immer. Es ist handlich, aber hässlich, es sei denn, Sie gehen zu Extremen, um es zu formatieren und die interstitiellen Ausdrücke zu vereinfachen.

Sie sind nicht so schwer zu verstehen, wenn Sie ein paar Mal über sie hinweggelaufen sind und erkennen, dass es ein Idiom ist. Es ist jedoch einfacher, eine korrekte switch-Anweisung zu verstehen. Es besteht auch eine geringere Chance, einen Doppelpunkt falsch zu platzieren und alles auf eine schwer zu beschreibende Weise zu vermasseln.

Verwandte Themen