Ist es üblich, bestimmte Werte als Zeichenfolgen zu speichern?

19

Das ist ein sehr vager Titel, aber ich könnte mir keinen besseren Weg vorstellen, ihn auszudrücken. Aber denken Sie nur als Beispiel an die Richtung, in die sich ein Charakter in einem Spiel bewegt. Es fühlt sich einfach falsch an, eine Schnur zu verwenden und dann Dinge wie zu tun if(character.direction == "left"). Es scheint mir, dass es zu viel Raum für alberne Fehler lässt, wie das versehentliche Verwenden von Leftoder loder was auch immer anstelle von left. Sind meine Vermutungen richtig? Wenn ja, wie lässt sich so etwas am besten erreichen?

Cal7
quelle
10
du meinst, neben enums ob deine sprache diese unterstützt?
Hoffmale
12
Du meinst Stringly Typed ?
RubberDuck
Einige Sprachen können keine anderen Werte als Zeichenfolgen speichern, z bash.
Mouviciel
Ich weiß nicht warum, aber ich erinnerte mich an das "Define" in C. Sie können Dinge tun wie: #define false true
linuxunil

Antworten:

28

Wenn die von Ihnen verwendete Sprache die Verwendung von Aufzählungen unterstützt, würde ich sie verwenden. Hiermit können Sie die Anzahl der verfügbaren Optionen für einen bestimmten Typ begrenzen. zB in Java:

public enum Direction {
    LEFT,
    RIGHT,
    UP,
    DOWN
}
Vielleicht_Faktor
quelle
2
Diese Antwort trägt nicht zum Verständnis des OP-Problems bei. Ich sehe hier keine Argumentation, nur eine Meinung, die auf Sprachen mit Klasse enumwie Java beschränkt ist. Viele Sprachen (z. B. VBA) haben enum, aber es ist möglicherweise nicht die beste Option, da es nicht die gleiche Zukunftssicherheit bietet. Siehe meine Antwort für eine Diskussion darüber, warum enumallein eine unvollständige, oft spröde und sprachspezifische Lösung ist.
sqykly
12

Es ist eine schreckliche Praxis, im Code wörtliche Zeichenfolgen (oder magische Zahlen) zu verwenden.

Aufzählungen sind gut oder verwenden zumindest Konstanten (Aufzählungen sind natürlich nur ein Wrapper-Typ für eine oder mehrere verwandte Konstanten).

const string LEFT = "left"
if (someThing == LEFT) { doStuff(); }

Dieser einfache Schalter hat so viele Vorteile, dass ich gar nicht wüsste, wo ich anfangen soll, sie zu erklären (zumindest nicht ohne etwas Kaffee). Lesen Sie die magischen Zahlen nach, es ist dasselbe exakte Konzept, das nur auf einen Zahlenwert anstelle eines Zeichenfolgenwerts angewendet wird.

Hier ist ein kurzer Hinweis, ich bin sicher, dass es noch Hunderte gibt: /programming/47882/what-is-a-magic-number-and-why-is-it-bad

JLeach
quelle
1
Das Problem, das ich bei diesem Ansatz habe, ist, dass Sie Tippfehler wie --const string LEFT = "letf" bekommen - während Sie mit Enums arbeiten, die beim Kompilieren abgefangen werden.
Pieter B
@PieterB - Ich dachte, die Frage von OP war weit genug und das Beispiel für "left" war nur ein willkürliches Beispiel - wo nicht alle Fälle mit einer Aufzählung übereinstimmen würden. Ich bin damit einverstanden, dass für eine Reihe von Anweisungen speziell eine Aufzählung die beste Wahl ist, aber meine Antwort sollte allgemeiner sein: "Wenn Sie es wörtlich ausdrücken, machen Sie es zumindest zu einer Konstanten" (Aufzählungen natürlich, eine Art von Konstante sein)
jleach
3
Ich hatte das Vergnügen, mit einer Anwendung zu arbeiten, die die Tage des Wochenendes als jene Tage festlegte, deren Name mit einem "s" beginnt. Sehr überrascht waren sie über die "Tatsache", dass Frankreich bei der Internationalisierung der Bewerbung nur ein eintägiges Wochenende hatte.
Pieter B
4
Nennen wir es Mikrooptimierung, aber einige Sprachen interpretieren dies möglicherweise als Wertevergleich und verschwenden viel Zeit damit, jedes Zeichen in der Zeichenfolge zu überprüfen. Noch wahrscheinlicher ist es, wenn Sie wie der Fragesteller vorgehen und mit der fest codierten Zeichenfolge "left" vergleichen. Wenn der konstante Wert keine Zeichenfolge sein muss (dh, Sie geben ihn nicht aus), ist es besser, stattdessen einen const int zu verwenden.
Devsman
4

Kurze Antwort: Ja, Zeichenfolgen eignen sich nur für das Speichern und Zugreifen auf eine Folge von Textzeichen. Auch wenn die zugrunde liegenden Bits einer Abstraktion Zeichenfolgen sind, bietet es Vorteile, sie als Variablen oder Konstanten zu referenzieren .

Lange Antwort: Die meisten Sprachen bieten Typen an, die näher an der Domäne Ihres Problems liegen, und auch wenn dies nicht der Fall ist, verfügen sie wahrscheinlich über eine Methode, mit der Sie lefteine Entität definieren können, die sich von right(etc etc) unterscheidet. Das Verwandeln in eine Zeichenfolge mithilfe von verfällt "left"lediglich die Sprache und die hilfreichen Funktionen der IDE, z. B. die Fehlerprüfung. Auch wenn Sie verwenden müssen

left = "left";

Oder etwas Äquivalentes: Es hat Vorteile, die Zeichenfolge zu verwenden, wenn Sie im gesamten Code darauf verweisen. Beispielsweise,

if (player.direction == Left)

würde als Fehler bei der Kompilierung erkannt (bester Fall, Java und so) oder von einer IDE als falsch gekennzeichnet (schlimmster Fall, grundlegend und so).

Darüber hinaus lefthilft Ihnen der Begriff als referenzierbare Entität dabei, die Richtung zu berücksichtigen, in die Sie sich für den Richtungstyp entscheiden. Durch die Verwendung von "left"wird Richtung dazu verpflichtet, ein String. Wenn Sie eine bessere Abstraktion für den Typ finden oder erstellen, müssen Sie Ihren gesamten Codekörper durchsuchen und dabei jede Instanz von ändern "left". Eine Konstante oder Variable erfordert keine Änderungen, wenn der Typ ausgearbeitet ist.

Der Typ, den Sie wirklich wollen, ist spezifisch für Ihre Domain. Was hat Ihr Code mit Ihrem zu tun left? Vielleicht möchten Sie die x-Achse einer Textur oder eines Sprites spiegeln, die / das nach links zeigt oder sich vorwärts bewegt. In diesem Fall möchten Sie möglicherweise leftein Objekt mit einer Eigenschaft oder Methode erstellen, die dieses Verhalten widerspiegelt, wobei Ihr rightObjekt das entgegengesetzte nicht gespiegelte Ergebnis aufweist. Sie können diese Logik in einem Objekt ausführen, das die Sprites oder Texturen darstellt. In diesem Fall leiden Sie erneut unter der Verwendung "left"anstelle der leftoben genannten Gründe.

In Java (und wahrscheinlich in anderen Sprachen, die ich noch nicht kenne) enumist dies eine gute Alternative, da es in Java enumgenauso nützlich ist, wenn final classeine endliche Menge von Instanzen vorhanden ist. Sie können Verhalten definieren, wenn Sie diese benötigen, und Sie können problemlos zu einer offenen Klasse außerhalb der Datei wechseln, in der das deklariert wird enum, aber viele Sprachen sehen das enumals primitiven Typ oder erfordern eine spezielle Syntax. Dies führt enumdazu, dass Code verloren geht, der nichts damit zu tun hat und möglicherweise später korrigiert werden muss. Stellen Sie sicher, dass Sie das Konzept Ihrer Sprache verstehen, enumbevor Sie die Option in Betracht ziehen.

sqykly
quelle
2

Sie haben Ihre Sprache nicht angegeben, aber um eine generische Antwort zu geben, sollten Sie Zeichenfolgen verwenden, wenn Sie den Text tatsächlich benötigen, und nicht, um etwas darzustellen. Das Beispiel, das Sie zum Beispiel angegeben haben, wäre in Produktionssoftware einfach nicht akzeptabel.

Jede Sprache hat verschiedene grundlegende Datentypen, und Sie sollten den für die Aufgabe am besten geeigneten Datentyp verwenden. Um Ihr Beispiel zu verwenden, könnten Sie numerische Konstanten verwenden, um verschiedene Zustände darzustellen. Left könnte also einen Wert von Null haben und right wäre eins. Abgesehen von dem von Ihnen genannten Grund belegen numerische Werte weniger Speicherplatz und es ist immer schneller, Zahlen zu vergleichen, als mehrere Zeichenfolgen zu vergleichen.

Verwenden Sie, wie bereits vorgeschlagen, Aufzählungen, wenn Ihre Sprache dies zulässt. In Ihrem konkreten Beispiel ist es eindeutig die bessere Wahl.

Nagev
quelle
Geschwindigkeit und Gedächtnis sind unwahrscheinlich. Das heißt, lieber Enums oder Konstanten. Zeichenfolgen sind sinnvoller, wenn die Daten aus einem Textformat stammen, z. B. XML, aber auch dann mit Groß- oder Kleinschreibung konsistent sind. Oder konvertieren Sie immer , z. if (uppercase(foo) == "LEFT")
user949300
2
@ user949300 Das Konvertieren von Zeichenfolgen in Groß- oder Kleinbuchstaben ist ebenfalls nicht zuverlässig. Es besteht die Möglichkeit, dass sich jemand dafür entscheidet, ein anderes Gebietsschema zu besuchen (oder das Geschäft dort zu erweitern), wie die Türkei , und naive Vergleiche von Zeichenfolgen in Groß- oder Kleinschreibung (oder in Kleinschreibung) unterbricht.
8bittree
Sich um Geschwindigkeit und Gedächtnis zu kümmern, ist immer eine gute Übung, sie sind keine unendlichen Ressourcen. Obwohl es in Ordnung ist, dies bewusst zu opfern, um die Lesbarkeit zu verbessern oder einen anderen Kompromiss einzugehen, was hier nicht der Fall ist. Eine Nichtbeachtung kann jedoch leicht zu trägen oder verschwenderischen Anwendungen führen.
Nagev
Das Vergleichen von Zeichenfolgen ist wahrscheinlich 50-mal langsamer als das Vergleichen von Aufzählungen. Meistens spielt es keine Rolle. Wenn Ihr Code jedoch schon ein bisschen langsam ist, kann dieser Unterschied dazu führen, dass er inakzeptabel ist. Wichtiger ist natürlich die Tatsache, dass der Compiler Ihnen bei Rechtschreibfehlern nicht helfen kann, wenn Sie Zeichenfolgen verwenden.
gnasher729
1

Verwenden Sie einfach den Datentyp, der in Ihrer Situation sinnvoll ist.

Die Verwendung des stringTyps als zugrunde liegende Kommunikation zwischen / innerhalb von Anwendungen ist von Natur aus kein Problem. In der Tat ist es manchmal vorzuziehen , Zeichenfolgen zu verwenden: Wenn Sie eine öffentliche API haben, kann es wünschenswert sein, dass die Werte, die in die API eingegeben und daraus entfernt werden, für den Menschen lesbar sind. Dies erleichtert es Leuten, die Ihre API verwenden, zu lernen und Fehler zu beheben.

Das eigentliche Problem mit Ihrem Code besteht darin , den Wert zu wiederholen .

Mach das nicht:

if (direction == 'left') {
  goLeft();
}

Wenn Sie in einer dieser Bedingungen oder bei anderen Verwendungszwecken von "left" einen Tippfehler gemacht haben, können Sie möglicherweise keine effektive Suche auf Codebasis durchführen, da Sie sich vertippt haben!

Verwenden Sie stattdessen Code gegen eine Aufzählung oder eine Konstante. Dies hängt davon ab, welcher Datentyp in den von Ihnen verwendeten Sprachen benötigt wird.

Das heißt, Sie LEFTsollten in Ihrer Bewerbung einmal und nur einmal vergeben sein . Und der Rest Ihres Codes sollte diese Aufzählungen oder Konstanten nutzen:

const string LEFT = "left";

if (direction == LEFT) {
  goLeft();
}

Auf diese Weise können Sie den Datentyp, den Sie später für Ihre Anweisungen verwenden, auch einfacher ändern, wenn Sie dies wünschen.

Svidgen
quelle
1

Ist es schlechte Praxis?

Wahrscheinlich ja, aber es hängt davon ab , was Sie genau tun und welche Programmiersprache Sie verwenden.

In Ihrem Beispiel können wir darauf schließen, dass es eine kleine und für immer festgelegte Menge von Werten gibt, die eine Richtung annehmen könnte. In diesem Fall hat die Verwendung einer Zeichenfolge keine Vorteile und einige eindeutige Nachteile. Für dieses Beispiel:

  • Ein enumTyp wäre vorzuziehen, wenn Ihre Programmiersprache dies unterstützt.
  • Ansonsten sind benannte Integer-Konstanten die Lösung mit einer einzigen Definition für die Konstanten.

Die Antwort kann jedoch unterschiedlich sein, wenn der Wertesatz dynamisch veränderbar ist oder sich im Laufe der Zeit weiterentwickeln muss. In den meisten Sprachen enumerfordert das Ändern eines Typs (z. B. zum Hinzufügen oder Entfernen eines Werts) eine vollständige Neukompilierung. (Wenn Sie beispielsweise einen Enum-Wert in Java entfernen, wird die Binärkompatibilität beeinträchtigt.) Dasselbe gilt für Konstanten für benannte Ganzzahlen.

In solchen Szenarien ist möglicherweise eine andere Lösung erforderlich, und die Verwendung von Zeichenfolgen ist eine der Optionen. (Und Sie könnten String-Literale und benannte Konstanten kombinieren ... wenn das Szenario einen festen Kern mit dynamischen Erweiterungen beinhaltet.)


Wenn Sie in Java implementieren, character.direction == "left"ist dies aus einem anderen Grund eine schlechte Praxis. Sie sollten diese Option nicht ==zum Vergleichen von Zeichenfolgen verwenden, da sie die Objektidentitäten und nicht die Zeichenfolgengleichheit testet. (Es würde funktionieren, wenn Sie sicherstellen könnten, dass alle Instanzen der "left"Zeichenfolge interniert wurden, dies jedoch eine Analyse der gesamten Anwendung erfordert.)

Stephen C
quelle
1
Was für immer fix zu sein scheint, entpuppt sich oft als gar nicht so fix. Aus vier Richtungen können beispielsweise acht werden.
Jimmy T.
@ JimmyT. - Das hängt vom Kontext ab. Wenn Sie beispielsweise in einem Spiel die Anzahl der Richtungen, in die sich ein Charakter bewegen kann, von 4 auf 8 ändern, werden die Spielregeln und der Code, der die Regeln implementiert, komplett überarbeitet. Die Verwendung Stringzur Darstellung der Richtungen würde einen Unterschied von nahezu Null in Bezug auf den Arbeitsaufwand zur Durchführung der Änderungen bedeuten. Ein vernünftigerer Ansatz ist, davon auszugehen, dass sich die Anzahl der Richtungen nicht ändert, und zu erkennen, dass Sie in beiden Fällen eine Menge Arbeit zu tun hätten , wenn sich die Spielregeln so grundlegend geändert hätten.
Stephen C
@JimmyT - Ich stimme dir vollkommen zu, dass ich das schon oft gesehen habe. Die Entwickler haben die Abkürzung für die Neudefinition des Strings gewählt. So wird beispielsweise aus product = "Option" product = "Option_or_Future", was die Bedeutung des Codes völlig beeinträchtigt.
Chris Milburn
-3

Wie vorgeschlagen, sollten Sie Enums verwenden. Allerdings ist es meiner Meinung nach nicht ausreichend, nur die Enum als Ersatz für die Strigns zu verwenden. In Ihrem speziellen Beispiel sollte die Geschwindigkeit des Spielers ein physikalischer Vektor sein:

class Vector {
  final double x;
  final double y;
}

Dieser Vektor sollte dann verwendet werden, um die Spielerposition bei jedem Tick zu aktualisieren.

Sie können dies dann mit einer Aufzählung für eine bessere Lesbarkeit kombinieren:

enum Direction {
  UP(new Vector(0, 1)),
  RIGHT(new Vector(1, 0)),
  DOWN(new Vector(0, -1)),
  LEFT(new Vector(-1, 0));

  private Vector direction;

  Direction(Vector v) {
    this.direction = v;
  }

  public Vector getVector() { return this.direction; }
}
marstato
quelle
4
-1 Du gehst viel zu weit in das Beispiel, das er gibt.
Pieter B