it-swarm.dev

Dois-je utiliser des instructions switch ou de longues chaînes if ... else?

Souvent, quand j'entends parler de l'instruction switch, elle est repoussée comme un moyen de remplacer les longues chaînes if ... else. Mais il semble que lorsque j'utilise l'instruction switch, j'écris plus de code que j'écrirais simplement si ... sinon. Vous avez également d'autres problèmes comme garder toutes les variables pour tous les appels dans la même portée .

Voici un code qui représente le flux que j'écris normalement ( grâce à diam )

String comment;   // The generated insult.
int which = (int)(Math.random() * 3);  //  Result is 0, 1, or 2.

if (which == 0) {
    comment = "You look so much better than usual.";
} else if (which == 1) {
    comment = "Your work is up to its usual standards.";
} else if (which == 2) {
    comment = "You're quite competent for so little experience.";
} else {
    comment = "Oops -- something is wrong with this code.";
}

Ensuite, ils veulent que je remplace cela par ceci:

String comment;   // The generated insult.
int which = (int)(Math.random() * 3);  //  Result is 0, 1, or 2.

switch (which) {
    case 0:  
             comment = "You look so much better than usual.";
    break;
    case 1:  
             comment = "Your work is up to its usual standards.";
    break;
    case 2:  
             comment = "You're quite competent for so little experience.";
    break;
    default: 
             comment = "Oops -- something is wrong with this code.";
}

On dirait beaucoup plus de code dans une syntaxe beaucoup plus maladroite. Mais y a-t-il vraiment un avantage à utiliser l'instruction switch?

36
TheLQ

Pour cette situation particulière, il me semble que if et case sont de mauvais choix. J'utiliserais un tableau simple:

String comments[] = {
    "You look so much better than usual.",
    "Your work is up to its usual standards.",
    "You're quite competent for so little experience."
};

String comment = comments[(int)(Math.random() * 3)];

En remarque, vous devez généralement calculer le multiplicateur en fonction de la taille du tableau plutôt que de coder en dur le 3.

Quant à savoir quand vous utiliseriez un cas/commutateur, la différence par rapport à une cascade d'instructions if (ou au moins une différence majeure) est que switch peut optimiser semi-automatiquement en fonction du nombre et de la densité des valeurs, tandis qu'une cascade d'instructions if laisse au compilateur peu de choix mais de générer du code tel que vous l'avez écrit, tester une valeur après l'autre jusqu'à ce qu'elle trouve une correspondance. Avec seulement trois cas réels, ce n'est guère une préoccupation, mais avec un nombre suffisant, cela peut/pourrait être significatif.

57
Jerry Coffin

Le problème avec le if...else if... chaîne est que lorsque je viens le lire, je dois examiner chaque condition if pour comprendre ce que fait le programme. Par exemple, vous pourriez avoir quelque chose comme ceci:

if (a == 1) {
    // stuff
} else if (a == 2) {
    // stuff
} else if (a == 3) {
    // stuff
} else if (b == 1) {
    // stuff
} else if (b == 2) {
    // stuff
}

(évidemment, pour un petit nombre de déclarations comme celle-ci, ce n'est pas si mal)

Je n'aurais aucun moyen de savoir que vous avez modifié la variable de condition à mi-parcours sans lire chaque instruction. Cependant, comme un switch vous limite à une seule variable de condition, je peux voir en un coup d'œil ce qui se passe.

À la fin de la journée, cependant, je ne préférerais ni switch ni une chaîne de if...else if. Souvent, une meilleure solution est une sorte de table de saut ou de dictionnaire pour les cas comme dans la question d'origine, ou le polymorphisme (si votre langue le supporte). Ce n'est pas toujours possible, bien sûr, mais je chercherais une solution qui évite switch dans un premier temps ...

23
Dean Harding
switch (which) {
  case 0: comment = "String 1"; break;
  case 1: comment = "String 2"; break;
  case 2: comment = "String 3"; break;
  default: comment = "Oops"; break;
}

La manière ci-dessus d'écrire ce type de boîtier de commutateur est assez courante. La raison pour laquelle vous vous sentiez le boîtier de commutation si plus volumineux est parce que votre corps n'était qu'une seule ligne et avec un boîtier de commutation, vous aviez également besoin de la déclaration de rupture. Donc, le boîtier du commutateur avait deux fois la taille du corps de sinon. Avec un code plus substantiel, l'instruction break n'ajoutera pas grand-chose au corps. Pour le corps d'une seule ligne, il est courant d'écrire le code sur la même ligne que l'instruction case.

Comme d'autres l'ont déjà mentionné, un cas de commutateur rend l'intention plus claire, vous voulez prendre une décision basée sur la valeur d'une seule variable/expression. Mes commentaires sont purement d'un point de vue de lisibilité et non basés sur les performances.

14
aufather

Dans ce cas, l'instruction switch correspond plus clairement à l'intention du code: choisissez une action à effectuer en fonction d'une seule valeur.

Les déclarations if, d'un autre côté, sont beaucoup plus difficiles à lire - vous devez les regarder toutes pour être sûr de ce qui se passe. Pour moi, c'est moins de code (même si le nombre de caractères peut être légèrement plus élevé) car il y a moins à analyser mentalement.

8
FinnNk

Je suis d'accord avec Jerry qu'un tableau de chaînes est meilleur pour ce cas particulier, mais qu'en général il vaut mieux utiliser une instruction switch/case qu'une chaîne d'autre chose. C'est plus facile à lire, et parfois le compilateur peut faire un meilleur travail d'optimisation de cette façon, mais il y a aussi un autre avantage: c'est beaucoup plus facile à déboguer.

Lorsque vous appuyez sur ce commutateur, vous n'avez qu'à faire un pas une fois pour vous retrouver sur la bonne branche, au lieu de franchir soigneusement plusieurs instructions if une à la fois, et peut-être d'appuyer sur la touche trop rapidement et de la dépasser et de manquer quelque chose et d'avoir recommencer à zéro.

8
Mason Wheeler

Je préfère changer dans ce genre de cas, cela correspond beaucoup mieux au point du code, exécutez une instruction différente pour chaque valeur d'entrée différente. Le if..else agit plutôt comme un "truc" pour obtenir le même effet.

switch les instructions sont également plus propres, il est facile d'avoir une faute de frappe cachée dans toutes ces ==

De plus, pour les gros blocs en C, le changement est plus rapide.

else..if peut être plus approprié lorsque vous avez quelque chose comme des plages (entre 1 et 100, faites ceci, entre 100 et 200 faites cela), ou en C, lorsque vous essayez de basculer avec des éléments comme des chaînes (c'est possible dans d'autres langues ). C'est pareil.

J'ai tendance à utiliser beaucoup de commutateurs lorsque je programme en C.

3
Khelben

Je n'aime généralement pas l'une ou l'autre approche. Commutateur long ou si les instructions ne demandent qu'à être refactorisées en une abstraction orientée objet (mais votre exemple, je le classerais comme court, pas long).

J'emballerais personnellement ce type de code dans une méthode d'assistance distincte.

private string GetInsult()
{
    int which = (int)(Math.random() * 3);  //  Result is 0, 1, or 2.

    switch (which) {
        case 0: return "You look so much better than usual.";
        case 1: return "Your work is up to its usual standards.";
        case 2: return "You're quite competent for so little experience.";
        default: return "Oops -- something is wrong with this code.";
    }
}

public void Foo()
{
    string comment = GetInsult();
    Print(comment);
}

Placer le commutateur dans une méthode distincte vous permet de placer des instructions de retour directement à l'intérieur de l'instruction switch (au moins en c #), éliminant ainsi le besoin d'instructions break, ce qui rend le code beaucoup plus facile à lire.

Et c'est à mon humble avis beaucoup plus agréable que l'approche if/else if/else if.

2
Pete

Choisissez quelque chose qui est efficace, concis, puis document non seulement ce que vous avez fait, mais pourquoi.

Le code peut être revisité, et pas toujours par son auteur d'origine.

Il y a des moments où vous pouvez délibérément choisir une implémentation plutôt qu'une autre parce que vous êtes avant-gardiste sur le code qui n'existe pas.

2
Walt Stoneburner

L'une des choses qui rend le style C/C # switch particulièrement ennuyeux est l'insistance sur la valeur case qui est littérale. Une bonne chose à propos de VB/VB.NET est que select/case permet à chaque cas d'être n'importe quelle expression booléenne. Cela est pratique. Dans la mesure où une série d'expressions booléennes s'excluant mutuellement est souvent utile, une série d'if/else if est plus flexible, sans oublier d'être plus efficace à taper et à lire.

0
Joel Brown

En python, il n'y a pas d'instruction switch, car si/Elif/else est Nice:

a = 5

if a==1:
    print "do this"
Elif a == 2:
    print "do that"
Elif a == 3:
    print "do the other"
Elif 3 < a < 9:
    print "do more"
Elif 9 <= a < 15:
    print "do nothing"
else:
    print "say sorry"

C'est simple, non?

0