È una cattiva pratica memorizzare determinati valori come stringhe?


19

È un titolo molto vago ma non riesco a pensare a un modo migliore per esprimerlo. Ma, solo per fare un esempio, pensa alla direzione in cui si sta muovendo un personaggio in un gioco. È semplicemente sbagliato usare una stringa e fare cose del genere if(character.direction == "left"). Mi sembra che si lascia troppo spazio per errori sciocchi, come accidentalmente utilizzando Lefto lo qualsiasi altra cosa al posto di left. I miei sospetti sono corretti? In tal caso, qual è il modo preferito per ottenere qualcosa del genere?


10
vuoi dire, oltre alle enumerazioni se la tua lingua supporta quelle?
hoffmale,



Alcune lingue non sono in grado di memorizzare valori diversi da quelli come stringhe, ad es bash.
mouviciel,

non so perché ma mi sono ricordato del "definisci" in C. Puoi fare cose come: #define false true
linuxunil

Risposte:


28

Se la lingua che stai utilizzando supporta l'uso di enum, li userei. Ti consente di limitare il numero di opzioni disponibili per un determinato tipo. ad es. in Java:

public enum Direction {
    LEFT,
    RIGHT,
    UP,
    DOWN
}

2
Questa risposta non contribuisce alla comprensione del problema OP; Non vedo alcun ragionamento qui, solo un'opinione limitata nell'ambito delle lingue con classe enumcome java. Sono disponibili molte lingue (ad es. VBA) enum, ma potrebbe non essere l'opzione migliore in quanto priva della stessa protezione per il futuro. Vedi la mia risposta per una discussione sul perché enumda solo è una soluzione incompleta, spesso fragile e specifica della lingua.
sqykly

12

È una pratica terribile usare stringhe letterali (o numeri magici) nel codice.

Gli enum sono buoni, o almeno usano le costanti (ovviamente gli enum sono solo un tipo di wrapper per una o più costanti correlate).

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

Questo semplice interruttore ha tanti vantaggi che non saprei nemmeno da dove cominciare a spiegarli (almeno non senza altro caffè). Letto su numeri magici, è lo stesso concetto esatto, applicato solo a un valore numerico anziché a un valore stringa.

Ecco un rapido riferimento, sono sicuro che ce ne sono altre centinaia: /programming/47882/what-is-a-magic-number-and-why-is-it-bad


1
Il problema che ho con questo approccio è che si ottengono errori di battitura come --const string LEFT = "letf" - mentre se si lavora con enum che viene catturato in fase di compilazione.
Pieter B,

@PieterB - Pensavo che la domanda dei PO fosse abbastanza ampia, e l'esempio di "lasciato" solo un esempio arbitrario - in cui tutti i casi non corrispondevano a un enum. Concordo sul fatto che per una serie di indicazioni in particolare, un enum è la scelta migliore, ma la mia risposta doveva essere più generica in quanto "se lo metti in un letterale, almeno lo rendi una costante" (enum, ovviamente, essendo un tipo di costante)
jleach il

3
Ho avuto il piacere di lavorare con un'applicazione che ha assegnato i giorni del fine settimana come quei giorni il cui nome inizia con una "s". Sono rimasti molto sorpresi dal "fatto" che quando hanno internazionalizzato la domanda che la Francia ha avuto solo un fine settimana di un giorno.
Pieter B,

4
Chiamalo microottimizzazione, ma alcune lingue potrebbero interpretarlo come un confronto di valori e perdere molto tempo a controllare ogni carattere nella stringa. Ancora più probabile se fai come ha fatto chi lo ha richiesto e confrontalo con la stringa hardcoded "left". Se non è necessario che il valore costante sia una stringa (ovvero non stamparla), è preferibile utilizzare invece una const int.
Devsman,

4

Risposta breve: Sì, le stringhe non sono ideali per attività diverse dall'archiviazione e dall'accesso a una sequenza di caratteri testuali, e anche se i bit sottostanti di un'astrazione sono stringhe, ci sono vantaggi nel riferirle come variabili o costanti .

Risposta lunga: la maggior parte delle lingue offre tipi più vicini al dominio del problema e, anche se non lo fanno, probabilmente hanno un metodo con il quale è possibile definire leftun'entità diversa da right(ecc. Ecc.). Trasformarlo in una stringa utilizzando "left"è semplicemente la perdita della lingua e la funzionalità utile di IDE come il controllo degli errori. Anche se devi usare

left = "left";

o qualcosa di equivalente, ha dei vantaggi nell'usare la stringa quando ci si riferisce a tutto il codice. Per esempio,

if (player.direction == Left)

verrebbe rilevato come errore di compilazione (nel migliore dei casi, java e simili) o contrassegnato da qualsiasi IDE degno dei suoi bit come errato (nel peggiore dei casi, di base e simili).

Inoltre, la nozione di leftentità riferibile ti aiuterà a soddisfare qualsiasi direzione decidi di seguire il tipo di direzione. Usando "left", la direzione si impegna a essere a String. Se trovi o crei un'astrazione migliore per il tipo, devi andare a caccia attraverso l'intero corpo del codice cambiando ogni istanza di "left". Una costante o variabile non richiederà alcuna modifica se il tipo viene elaborato.

Il tipo che desideri davvero è particolare per il tuo dominio. Che cosa prevede di fare il tuo codice con il tuo left? Forse vorrai rispecchiare l'asse x di una trama o uno sprite che è rivolto a sinistra o si sposta in avanti; in tal caso, potresti voler creare leftun oggetto con una proprietà o un metodo che rifletta quel comportamento, con l' rightoggetto con il risultato opposto non speculare. Potresti fare quella logica in un oggetto che rappresenta gli sprite o le trame, nel qual caso soffrirai di nuovo per l'uso "left"invece che leftper i motivi sopra indicati.

In Java (e probabilmente in altre lingue che non conosco ancora), enumè una buona alternativa perché in Java enumè utile final classcon un set limitato di istanze. Puoi definire comportamenti se ne hai bisogno e puoi passare a una classe aperta senza problemi al di fuori del file che dichiara il enum, ma molte lingue vedono un enumtipo primitivo o richiedono una sintassi speciale da usare. Ciò perde il enumcappuccio per codice che non ha alcuna attività commerciale e potrebbe essere necessario correggerlo in seguito. Assicurati di comprendere il concetto di lingua enumprima di prendere in considerazione l'opzione.


2

Non hai specificato la tua lingua, ma per dare una risposta generica, dovresti usare le stringhe quando hai davvero bisogno del testo, non per rappresentare qualcosa. L'esempio fornito, ad esempio, non sarebbe semplicemente accettabile nel software di produzione.

Ogni lingua ha vari tipi di dati di base e dovresti usare quello più appropriato per l'attività. Per usare il tuo esempio, puoi usare costanti numeriche per rappresentare stati diversi. Quindi sinistra potrebbe avere un valore pari a zero e destra sarebbe uno. Oltre al motivo che hai citato, i valori numerici occupano meno spazio (memoria) ed è sempre più veloce confrontare i numeri piuttosto che confrontare più stringhe di caratteri.

Come è stato suggerito, utilizzare le enumerazioni se la tua lingua lo consente. Nel tuo esempio specifico, è chiaramente la scelta migliore.


È improbabile che la velocità e la memoria contino. Detto questo, preferisci enumerazioni o costanti. Le stringhe hanno più senso se i dati provengono da un formato di testo, ad esempio XML, ma anche in questo caso devono essere coerenti con tutti i limiti o tutti i non -aps. Oppure, converti sempre , e g. if (uppercase(foo) == "LEFT")
user949300

2
@ user949300 Anche la conversione di stringhe in maiuscolo o minuscolo non è affidabile. C'è la possibilità che qualcuno possa decidere di visitare un altro locale (o espandere l'attività lì), come la Turchia , e di rompere i confronti ingenui delle stringhe di maiuscole / minuscole.
8

Prendersi cura della velocità e della memoria è sempre una buona pratica, non sono risorse infinite. Anche se è ok sacrificarlo consapevolmente per motivi di leggibilità o qualche altro compromesso, il che non è il caso qui. Ma non preoccuparsene può facilmente portare ad applicazioni lente o dispendiose.
Nagev,

Il confronto di stringhe è probabilmente 50 volte più lento rispetto al confronto di enumerazioni. Il più delle volte non importa. Ma se il tuo codice è già un po 'lento, quella differenza potrebbe renderlo inaccettabile. Più importante ovviamente è il fatto che il compilatore non può aiutarti con errori di ortografia se usi le stringhe.
gnasher729,

1

Usa semplicemente il tipo di dati che ha senso nella tua situazione.

L'uso del stringtipo come comunicazione inter / intra-applicazione sottostante non è intrinsecamente un problema. In effetti, a volte è preferibile utilizzare le stringhe: se si dispone di un'API pubblica, può essere desiderabile che i valori in entrata e in uscita dall'API siano leggibili dall'uomo. Semplifica l'apprendimento e il debug delle persone che usano la tua API.

Il vero problema con il tuo codice sta nel ripetere il valore.

Non farlo:

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

Se hai fatto un refuso in uno di questi condizionali o altri usi di "sinistra" da qualche parte, potresti non essere in grado di eseguire in modo efficace una ricerca a livello di codice, perché l'hai scritto male!

Invece, codifica contro un'enumerazione o una costante, a seconda di quale supporto supporta il tipo di dati di cui hai bisogno nella lingua o nelle lingue che stai utilizzando.

Ciò significa che LEFTdovrebbe essere assegnato una volta sola e una sola volta nella domanda. Inoltre, il resto del codice dovrebbe sfruttare tali enumerazioni o costanti:

const string LEFT = "left";

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

Questo ti consente anche di modificare più facilmente il tipo di dati che usi per le tue indicazioni in seguito, se lo desideri.


1

È una cattiva pratica?

Probabilmente sì, ma dipende esattamente da quello che stai facendo e anche dal linguaggio di programmazione che stai usando.

Nel tuo esempio, possiamo dedurre che esiste un piccolo e fisso insieme di valori che una direzione potrebbe prendere. In questo caso, non ci sono vantaggi nell'uso di una stringa e alcuni svantaggi definiti. Per questo esempio:

  • Un enumtipo sarebbe preferibile, se il tuo linguaggio di programmazione lo supporta.
  • Altrimenti, le costanti intere con nome sono la strada da percorrere, con un'unica definizione per le costanti.

Ma la risposta potrebbe essere diversa se l'insieme di valori è dinamicamente modificabile o deve evolversi nel tempo. Nella maggior parte delle lingue, la modifica di un enumtipo (ad es. Per aggiungere o rimuovere un valore) richiede una ricompilazione completa. (Ad esempio, la rimozione di un valore enum in Java interrompe la compatibilità binaria.) E lo stesso vale per le costanti intere con nome.

In scenari come questo potrebbe essere necessaria un'altra soluzione e l'utilizzo delle stringhe è una delle opzioni. (E potresti combinare valori letterali di stringa e costanti nominate ... se lo scenario implica un nucleo fisso con estensioni dinamiche.)


Se stai implementando in Java, character.direction == "left"è una cattiva pratica per un altro motivo. Non si dovrebbe usare ==per confrontare le stringhe, perché sta testando le identità degli oggetti piuttosto che l'uguaglianza delle stringhe. (Funzionerebbe se si potesse garantire che tutte le istanze della "left"stringa sono state internate, ma ciò richiede l'analisi dell'intera applicazione.)


1
Ciò che sembra risolto per sempre risulta spesso non così risolto. Ad esempio, quattro direzioni possono diventare otto.
Jimmy T.,

@JimmyT. - Dipende dal contesto. Ad esempio, in un gioco, cambiare il numero di direzioni che un personaggio può spostare da 4 a 8 comporterebbe una revisione completa delle regole del gioco e il codice che implementa le regole. Usare Stringper rappresentare le direzioni farebbe quasi una differenza zero rispetto alla quantità di lavoro coinvolto per apportare le modifiche. Un approccio più sensato è supporre che il numero di direzioni non cambierà e riconoscere che avresti molto lavoro da fare in entrambi i modi se le regole del gioco cambiassero in modo così fondamentale.
Stephen C,

@JimmyT - Sono totalmente d'accordo che ho visto accadere molte volte, hai anche gli sviluppatori che prendono la scorciatoia per ridefinire la stringa, quindi, ad esempio, product = "Option" diventa product = "Option_or_Future" completamente degradando il significato del codice.
Chris Milburn,

-3

Come suggerito, dovresti usare Enums. Tuttavia, il solo utilizzo di Enum come sostituto di Strigns non è sufficiente. Nel tuo esempio particolare, la velocità del giocatore dovrebbe effettivamente essere un vettore per mezzo della fisica:

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

Questo vettore dovrebbe quindi essere usato per aggiornare la posizione del giocatore ad ogni tick.

È quindi possibile combinarlo con un enum per una maggiore leggibilità:

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; }
}

4
-1 Stai andando troppo oltre nell'esempio che dà.
Pieter B,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.