Apakah praktik yang buruk untuk menyimpan nilai-nilai tertentu sebagai string?


19

Judul yang sangat samar tapi saya tidak bisa memikirkan cara yang lebih baik untuk mengatakannya. Tapi, seperti contohnya, pikirkan tentang arah pergerakan karakter dalam permainan. Rasanya agak salah menggunakan string dan kemudian melakukan hal-hal seperti if(character.direction == "left"). Sepertinya saya bahwa ia meninggalkan terlalu banyak ruang untuk kesalahan konyol, seperti sengaja menggunakan Leftatau latau apa pun bukan left. Apakah kecurigaan saya benar? Jika demikian, apa cara yang disukai untuk mencapai sesuatu seperti ini?


10
maksud Anda, selain enum jika bahasa Anda mendukungnya?
hoffmale

12
Maksud Anda Stringly Typed ?
RubberDuck


Beberapa bahasa tidak dapat menyimpan nilai selain sebagai string, misalnya bash,.
mouviciel

tidak tahu mengapa tetapi saya ingat "define" di C. Anda dapat melakukan hal-hal seperti: #define false true
linuxunil

Jawaban:


28

Jika bahasa yang Anda gunakan mendukung penggunaan enum, saya akan menggunakannya. Ini memungkinkan Anda membatasi jumlah opsi yang tersedia untuk jenis tertentu. misalnya di Jawa:

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

2
Jawaban ini tidak berkontribusi untuk memahami masalah OP; Saya melihat tidak ada alasan di sini, hanya pendapat terbatas dalam cakupan untuk bahasa dengan classy enumseperti java. Banyak bahasa (mis. VBA) miliki enum, tetapi ini mungkin bukan pilihan terbaik karena tidak memiliki pembuktian yang sama di masa depan. Lihat jawaban saya untuk beberapa diskusi tentang mengapa enumsendirian adalah solusi yang tidak lengkap, sering rapuh, dan spesifik bahasa.
sqykly

12

Praktek yang mengerikan untuk menggunakan string literal (atau angka ajaib) dalam kode.

Enum baik, atau paling tidak menggunakan konstanta (enum tentu saja hanya tipe pembungkus untuk satu atau lebih konstanta terkait).

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

Peralihan sederhana ini memiliki begitu banyak keuntungan sehingga saya bahkan tidak tahu harus mulai dari mana menjelaskannya (setidaknya bukan tanpa kopi lagi). Baca tentang angka ajaib, itu konsep yang persis sama, hanya diterapkan pada nilai angka dan bukan nilai string.

Ini satu ref cepat, saya yakin ada ratusan lebih: /programming/47882/what-is-a-magic-number-and-why-is-it-bad


1
Masalah yang saya miliki dengan pendekatan ini adalah Anda mendapatkan kesalahan ketik seperti --const string LEFT = "letf" - sedangkan jika Anda bekerja dengan enum yang terperangkap pada waktu kompilasi.
Pieter B

@PieterB - Saya pikir pertanyaan OPs cukup luas, dan contoh untuk "meninggalkan" hanya contoh sewenang-wenang - di mana semua kasus tidak akan cocok dengan enum. Saya setuju bahwa untuk serangkaian arahan khusus, enum adalah pilihan terbaik, tetapi jawaban saya dimaksudkan untuk menjadi lebih umum dalam hal "jika Anda memasukkannya ke dalam literal, setidaknya buatlah sebuah konstanta" (enum, tentu saja, menjadi tipe konstan)
jleach

3
Saya merasa senang bekerja dengan aplikasi yang menetapkan hari akhir pekan sebagai hari-hari yang namanya dimulai dengan huruf "s". Sangat terkejut mereka tentang "fakta" bahwa ketika mereka menginternasionalkan aplikasi bahwa Prancis hanya memiliki akhir pekan satu hari.
Pieter B

4
Sebut saja optimasi mikro, tetapi beberapa bahasa mungkin menafsirkan ini sebagai perbandingan nilai dan membuang banyak waktu untuk memeriksa setiap karakter dalam string. Bahkan lebih mungkin jika Anda melakukan seperti yang dilakukan penanya dan membandingkannya dengan string hardcoded "kiri". Jika tidak perlu nilai konstan menjadi string (yaitu, Anda tidak mencetaknya), akan lebih baik menggunakan const int sebagai gantinya.
Devsman

4

Jawaban singkat: Ya, string tidak ideal untuk tugas apa pun selain menyimpan dan mengakses urutan karakter tekstual, dan bahkan jika bit yang mendasari abstraksi adalah string, ada manfaat untuk merujuknya sebagai variabel atau konstanta .

Jawaban panjang: sebagian besar bahasa menawarkan jenis yang lebih dekat ke domain masalah Anda, dan meskipun tidak, mereka mungkin memiliki beberapa metode yang dapat Anda definisikan leftsebagai entitas yang berbeda dari right(dll.). Mengubahnya menjadi string dengan menggunakan "left"hanyalah kehilangan bahasa dan fungsi IDE yang bermanfaat seperti pengecekan kesalahan. Bahkan jika Anda harus menggunakannya

left = "left";

atau sesuatu yang setara, itu memiliki keuntungan menggunakan string ketika Anda merujuknya di kode Anda. Sebagai contoh,

if (player.direction == Left)

akan dideteksi sebagai kesalahan waktu kompilasi (kasus terbaik, java, dan semacamnya) atau ditandai oleh IDE apa pun yang bernilai bitnya salah (kasus terburuk, dasar, dan semacamnya).

Selain itu, memiliki gagasan leftsebagai entitas yang dapat dirujuk akan membantu Anda mengakomodasi arah apa pun yang Anda putuskan untuk digunakan dengan tipe arah. Dengan menggunakan "left", arahan berkomitmen untuk menjadi a String. Jika Anda menemukan atau membuat abstraksi yang lebih baik untuk jenis ini, Anda perlu menelusuri seluruh badan kode Anda untuk mengubah setiap instance "left". Konstanta atau variabel tidak akan memerlukan perubahan apa pun jika jenisnya dielaborasi.

Jenis yang Anda inginkan adalah khusus untuk domain Anda. Apa yang akan dilakukan perencanaan kode Anda dengan kode Anda left? Mungkin Anda ingin mencerminkan sumbu x dari tekstur atau sprite yang menghadap ke kiri atau bergerak maju; Jika demikian, Anda mungkin ingin membuat leftobjek dengan properti atau metode yang mencerminkan perilaku itu, dengan rightobjek Anda memiliki hasil yang berlawanan tanpa cermin. Anda dapat melakukan logika itu pada objek yang mewakili sprite atau tekstur, dalam hal ini Anda akan menderita karena menggunakan "left"bukan leftkarena alasan yang disebutkan di atas.

Di Jawa (dan mungkin bahasa lain yang belum saya kenal), enumadalah alternatif yang baik karena di Jawa, enumsama bermanfaatnya final classdengan serangkaian contoh yang terbatas. Anda dapat mendefinisikan perilaku jika Anda membutuhkannya, dan Anda dapat beralih ke kelas terbuka tanpa kerepotan di luar file yang menyatakan enum, tetapi banyak bahasa melihat enumtipe primitif atau memerlukan sintaks khusus untuk digunakan. Itu bocor enumke kode yang tidak memiliki bisnis dengan itu dan mungkin perlu diperbaiki nanti. Pastikan Anda memahami konsep bahasa enumAnda sebelum mempertimbangkan opsi.


2

Anda tidak menentukan bahasa Anda, tetapi untuk memberikan jawaban umum, Anda harus menggunakan string ketika Anda benar-benar membutuhkan teks, bukan untuk mewakili sesuatu. Contoh yang Anda berikan misalnya tidak akan diterima dalam perangkat lunak produksi.

Setiap bahasa memiliki berbagai tipe data dasar dan Anda harus menggunakan yang paling sesuai untuk tugas tersebut. Untuk menggunakan contoh Anda, Anda bisa menggunakan konstanta numerik untuk mewakili status yang berbeda. Jadi kiri dapat memiliki nilai nol dan kanan akan menjadi satu. Selain alasan yang Anda sebutkan, nilai numerik membutuhkan lebih sedikit ruang (memori) dan selalu lebih cepat untuk membandingkan angka daripada membandingkan beberapa string karakter.

Seperti yang disarankan, gunakan enumerasi jika bahasa Anda memungkinkan. Dalam contoh spesifik Anda, itu jelas pilihan yang lebih baik.


Kecepatan dan memori sepertinya tidak penting. Yang mengatakan, lebih suka enum atau konstanta. String lebih masuk akal jika data berasal dari format teks, misalnya XML, tetapi itupun konsisten dengan semua batas, atau semua uncaps. Atau, selalu konversi , mis. if (uppercase(foo) == "LEFT")
user949300

2
@ user949300 Mengubah string ke semua huruf besar atau semua huruf kecil juga tidak dapat diandalkan. Ada kemungkinan bahwa seseorang mungkin memutuskan untuk mengunjungi lokal lain (atau memperluas bisnis di sana), seperti Turki , dan memecahkan perbandingan string yang naif (atau casing yang lebih rendah).
8bittree

Memperhatikan kecepatan dan memori selalu merupakan praktik yang baik, mereka bukan sumber daya tanpa batas. Meskipun tidak apa-apa untuk secara sadar mengorbankannya demi keterbacaan atau pertukaran lainnya, yang tidak terjadi di sini. Tetapi tidak mempedulikan mereka dapat dengan mudah menyebabkan aplikasi lamban atau boros.
Nagev

Membandingkan string cenderung 50 kali lebih lambat daripada membandingkan enum. Sebagian besar waktu itu tidak masalah. Tetapi jika kode Anda sudah agak lambat, perbedaan itu mungkin membuatnya tidak dapat diterima. Lebih penting tentu saja adalah kenyataan bahwa kompiler tidak dapat membantu Anda dengan kesalahan ejaan jika Anda menggunakan string.
gnasher729

1

Cukup gunakan tipe data yang masuk akal dalam situasi Anda.

Penggunaan stringtipe ini sebagai komunikasi inter / intra-aplikasi yang mendasarinya secara inheren bukan masalah. Bahkan, kadang-kadang lebih disukai menggunakan string: Jika Anda memiliki API publik, dapat diinginkan untuk nilai masuk dan keluar dari API agar dapat dibaca oleh manusia. Ini memudahkan orang yang menggunakan API Anda untuk belajar dan debug.

Masalah sebenarnya dengan kode Anda terletak pada pengulangan nilai.

Jangan lakukan ini:

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

Jika Anda membuat kesalahan ketik pada salah satu dari persyaratan ini atau penggunaan "kiri" lainnya di suatu tempat, Anda mungkin tidak dapat secara efektif melakukan pencarian berdasarkan basis kode untuk itu, karena Anda salah ketik!

Alih-alih, kode terhadap enumerasi atau konstanta - tergantung pada yang mendukung tipe data yang Anda butuhkan dalam bahasa yang Anda gunakan.

Itu berarti LEFTharus ditugaskan-ke sekali dan hanya sekali dalam aplikasi Anda. Dan, sisa kode Anda harus memanfaatkan enum atau konstanta tersebut:

const string LEFT = "left";

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

Ini juga memungkinkan Anda untuk lebih mudah mengubah tipe data yang Anda gunakan untuk arah Anda nanti, jika Anda mau.


1

Apakah ini praktik yang buruk?

Mungkin ya, tapi itu tergantung pada apa apa yang Anda lakukan, dan juga pada bahasa pemrograman yang Anda gunakan.

Dalam contoh Anda, kami dapat menyimpulkan bahwa ada serangkaian nilai yang kecil dan tetap untuk selamanya yang bisa diambil oleh suatu arah. Dalam hal ini, tidak ada keuntungan dalam menggunakan string, dan beberapa kerugian yang pasti. Untuk contoh ini:

  • Sebuah enumjenis akan lebih baik, jika bahasa pemrograman Anda mendukung ini.
  • Kalau tidak, konstanta bilangan bulat bernama adalah cara untuk pergi, dengan definisi tunggal untuk konstanta.

Tetapi jawabannya mungkin berbeda jika himpunan nilai dimodifikasi secara dinamis, atau perlu berkembang seiring waktu. Dalam sebagian besar bahasa, mengubah enumjenis (misalnya untuk menambah atau menghapus nilai) membutuhkan kompilasi ulang yang lengkap. (Misalnya, menghapus nilai enum di Java merusak kompatibilitas biner.) Dan hal yang sama berlaku untuk konstanta integer bernama.

Dalam skenario seperti ini solusi lain mungkin diperlukan, dan menggunakan string adalah salah satu opsi. (Dan Anda bisa menggabungkan string literal dan konstanta bernama ... jika skenario memerlukan inti tetap dengan ekstensi dinamis.)


Jika Anda menerapkan di Jawa, character.direction == "left"praktik buruk karena alasan lain. Anda sebaiknya tidak menggunakan ==untuk membandingkan string, karena ini menguji identitas objek daripada kesetaraan string. (Ini akan berhasil jika Anda bisa menjamin bahwa semua instance dari "left"string telah diinternir, tetapi itu membutuhkan analisis seluruh aplikasi.)


1
Apa yang sepertinya diperbaiki untuk selamanya sering ternyata tidak begitu diperbaiki sama sekali. Empat arah misalnya bisa menjadi delapan.
Jimmy T.

@ JimmyT. - Itu tergantung pada konteksnya. Misalnya, dalam gim, mengubah jumlah arah yang dapat dipindahkan karakter dari 4 menjadi 8 akan memerlukan perombakan total aturan gim, dan kode yang menerapkan aturan. Menggunakan Stringuntuk mewakili arah akan membuat hampir nol perbedaan dengan jumlah pekerjaan yang terlibat untuk melakukan perubahan. Pendekatan yang lebih masuk akal adalah mengasumsikan bahwa jumlah arah tidak akan berubah, dan menyadari bahwa Anda akan memiliki banyak pekerjaan untuk dilakukan dengan cara lain jika aturan permainan berubah secara mendasar.
Stephen C

@ Jimim
Chris Milburn

-3

Seperti yang disarankan, Anda harus menggunakan Enums. Namun, hanya menggunakan Enum sebagai pengganti Strigns tidak cukup IMHO. Dalam contoh part Anda, kecepatan pemain seharusnya menjadi vektor melalui fisika:

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

Vektor ini kemudian harus digunakan untuk memperbarui posisi pemain setiap centang.

Anda kemudian dapat menggabungkannya dengan enum untuk keterbacaan yang lebih tinggi:

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 Anda terlalu jauh ke contoh yang dia berikan.
Pieter B
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.