2013-07-09 37 views
8

Tôi đang sử dụng big.NewInt (int64 (e)). Bytes() để chuyển đổi int32 thành mảng byte. Có cách nào thanh lịch hơn để thực hiện việc này không?Chuyển đổi mảng int32 sang byte trong go

Tôi hy vọng AQAB là base64 giá trị được mã hóa của e

http://play.golang.org/p/M46X7OpZpu

const e = 65537 

func base64Encode(b []byte) string { 
    return strings.TrimRight(base64.StdEncoding.EncodeToString(b), "=") 
} 

func main() { 
    fmt.Printf("exp %d\n", e) 

    b := make([]byte, 4) 
    binary.BigEndian.PutUint32(b, e) 
    fmt.Printf("b: BigEndian.PutUint32 %x (Bad) %s\n", b, base64Encode(b)) 

    b2 := make([]byte, 4) 
    binary.BigEndian.PutUint32(b2, e) 
    for i := range b2 { 
    if b2[i] != 0 { 
    b2 = b2[i:] 
    break 
    } 
    } 
    fmt.Printf("b2: BigEndian.PutUint32 %x (Good) %s\n", b2, base64Encode(b2)) 

    b4 := big.NewInt(int64(e)).Bytes() 
    fmt.Printf("b4: big.NewInt(int64(e)).Bytes() %x (Good) %s\n", b4, base64Encode(b4)) 
} 

Output:

exp 65537 
b: BigEndian.PutUint32 00010001 (Bad) AAEAAQ 
b2: BigEndian.PutUint32 010001 (Good) AQAB 
b4: big.NewInt(int64(e)).Bytes() 010001 (Good) AQAB 

exp 1 
b: BigEndian.PutUint32 00000001 (Bad) AAAAAQ 
b2: BigEndian.PutUint32 01 (Good) AQ 
b4: big.NewInt(int64(e)).Bytes() 01 (Good) AQ 

exp 1000000 
b: BigEndian.PutUint32 000f4240 (Bad) AA9CQA 
b2: BigEndian.PutUint32 0f4240 (Good) D0JA 
b4: big.NewInt(int64(e)).Bytes() 0f4240 (Good) D0JA 

Edit:

Tôi đã làm chuẩn b2 và b4:

b2 1000000000   68.1 ns/op   8 B/op   1 allocs/op 
b4 200000000   248 ns/op   90 B/op   3 allocs/op 

tôi sẽ sử dụng b2 cho bây giờ ...

Trả lời

5

Đối với loại công việc tôi nghĩ tùy chọn đầu tiên của bạn nên luôn luôn được sử dụng encoding/binary và, nếu đó là không đủ, Bitwise toán. Tuy nhiên, trong một số trường hợp cần thiết của việc sao chép dữ liệu quá lớn hoặc những an toàn giải pháp là quá chậm:

Trong khi tôi sẽ không gọi nó là thanh lịch, bạn có thể sử dụng unsafereflect * gói Go để làm điều này rất nhanh chóng. Chỉ cần nhớ, điều này không sao chép dữ liệu; thay vào đó, nó chỉ cung cấp cho bạn một "cái nhìn" khác của nó. Và cũng không an toàn có nghĩa là bạn cần phải rất cẩn thận- (xin chào bài kiểm tra đơn vị và đánh giá mã) và ghi nhớ rằng bạn đang phá vỡ số memory safety của Go. Tuy nhiên, khi tốc độ thực hiện là mối quan tâm thống trị và nhóm của bạn đồng ý unsafe được bảo hành, unsafe hiếm khi có thể bị đánh bại.

const BYTES_IN_INT32 = 4 

func UnsafeCaseInt32ToBytes(val int32) []byte { 
    hdr := reflect.SliceHeader{Data: uintptr(unsafe.Pointer(&val)), Len: BYTES_IN_INT32, Cap: BYTES_IN_INT32} 
    return *(*[]byte)(unsafe.Pointer(&hdr)) 
} 

func UnsafeCastInt32sToBytes(ints []int32) []byte {   
    length := len(ints) * BYTES_IN_INT32 
    hdr := reflect.SliceHeader{Data: uintptr(unsafe.Pointer(&ints[0])), Len: length, Cap: length} 
    return *(*[]byte)(unsafe.Pointer(&hdr)) 
} 

* Lưu ý: Bạn có thể muốn sử dụng SizeOf thay vì hằng số. Tôi thích sự ổn định hơn.

Cập nhật: đây là một số kết quả benchmark:

BenchmarkB2  20000000  88.7 ns/op 
BenchmarkB4  5000000  309 ns/op 
BenchmarkUnsafe 1000000000 2.25 ns/op 
+5

Không chỉ 'unsafe' an toàn bộ nhớ nghỉ ngơi, nó giới thiệu các vấn đề endian. –

+0

@larsmans: Cũng như tự thay đổi một chút; hơn nữa, bản thân 'encoding/binary' là endian-aware (http://golang.org/pkg/encoding/binary/#pkg-variables). – voidlogic

+7

Không, dịch chuyển là an toàn. 'x >> 24' sẽ nhận được 8 bit thứ tự cao của' x', bất kể tính cuối cùng. –

Các vấn đề liên quan