Saya perlu membuat banyak tag uint32 yang memetakan huruf ASCII. Misalnya tag "abcd" dikodekan sebagai 0x61626364 di mana setiap byte sesuai dengan kode ASCII huruf tersebut.

Solusi langsung adalah dengan menentukan nilai tag seperti ini

type Tag uint32

const Tag_abcd = Tag(0x61626364)

Tapi ini rawan kesalahan.

Solusi yang kurang rawan kesalahan adalah dengan mendefinisikan nilai tag dengan fungsi yang menerima huruf sebagai argumen.

const Tag_abcd = foo("abcd")

Atau seperti ini yang dapat dengan mudah dilakukan dengan makro di C

const Tag_abcd = bar('a','b','c','d')

Tetapi ini akan membutuhkan dukungan fungsi yang dievaluasi pada waktu kompilasi. Sejauh yang saya tahu, tidak mungkin dengan Go. Apakah saya benar ? Mungkinkah ada cara lain?

3
chmike 12 Mei 2021, 16:29

3 jawaban

Jawaban Terbaik

Anda dapat merakit konstanta menggunakan literal rune dan bit shift. Itu tidak akan terlalu kompak, tetapi akan "aman" (artinya Anda dapat melihat karakter di ekspresi konstan):

const TagABCD Tag = 'a'<<24 + 'b'<<16 + 'c'<<8 + 'd'

Atau Anda dapat menulisnya dalam beberapa baris, sehingga huruf-hurufnya disejajarkan dalam satu kolom:

const TagABCD2 Tag = 0 +
    'a'<<24 +
    'b'<<16 +
    'c'<<8 +
    'd'
4
icza 12 Mei 2021, 14:29

Untuk memperluas jawaban icza, dan untuk meningkatkan keterbacaan deklarasi tag, Anda dapat:

  • mendeklarasikan konstanta pembantu dalam bentuk <letter><number>, di mana <letter> adalah karakter ASCII terkait dan <number> adalah posisi karakter tersebut dalam tag 4 karakter.
  • bit-shift rune dengan iota* 8
  • buat konstanta tag dengan OR | dengan konstanta pembantu
import "fmt"

const (
    a1 uint32 = 'a'<<(iota*8)
    a2
    a3
    a4
)

// other similar const declarations for b1,b2,b3,b4 and so on
// must repeat the keyword const to reset iota

const Tag_abcd = a4 | b3 | c2 | d1

const Tag_ddba = d4 | d3 | b2 | a1

func main() {
    fmt.Printf("%x\n", Tag_abcd) // 61626364
    fmt.Printf("%x\n", Tag_ddba) // 64646261
}

Keuntungannya adalah:

  • deklarasi tag mungkin lebih mudah dibaca dan lebih mudah bagi pengelola manusia
  • pengidentifikasi pembantu dapat dengan mudah di-refactored dengan dukungan IDE

Kerugiannya adalah:

  • sumbernya mungkin menjadi lebih bertele-tele, tetapi Anda dapat menguranginya dengan mengisolasi const pembantu ke dalam file terpisah
  • untuk ASCII huruf besar, helper consts sebagai A1 akan diekspor, jadi Anda mungkin harus mengawali pengenal dengan _ atau trik serupa

YMMV

Tempat bermain

0
blackgreen 12 Mei 2021, 22:54

Anda dapat menggunakan go generate untuk mengurai nilai konstanta gabungan ke alokasi memori yang berbeda.

Cukup rumit untuk mempertahankan implementasi ini meskipun jika Anda memiliki tim yang perlu segera mengetahui apa yang dilakukannya dan kapan aman untuk memperbaikinya

0
Nacho Nieva 12 Mei 2021, 13:45