在不同类型的切片之间转换 [英] Convert between slices of different types

查看:90
本文介绍了在不同类型的切片之间转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从UDP套接字获得一个字节片段( [] byte ),并希望将其视为整数片段( [] int32 )而不改变底层数组,反之亦然。在C(++)中,我只是在指针类型之间进行转换;我会怎么做Go?

解决方案

正如其他人所说的,在Go中投射指针被认为是不好的形式。以下是适当的Go方式和C数组转换的等价例子。



警告:所有代码都未经测试。



正确的方法



在这个例子中,我们使用 encoding / binary 包来转换每个集合4个字节放入 int32 中。这更好,因为我们正在指定字节序。我们也没有使用 unsafe 包打破类型系统。

  importencoding / binary
$ b $ const SIZEOF_INT32 = 4 // bytes
$ b data:= make([] int32,len(raw)/ SIZEOF_INT32)
对于i:=范围数据{
//假设小尾数
data [i] = int32(binary.LittleEndian.Uint32(raw [i * SIZEOF_INT32:(i + 1)* SIZEOF_INT32]))



$ h $错误的方式(C数组转换)

在这个例子中,我们告诉Go忽略类型系统。这不是一个好主意,因为它可能会在Go的另一个实现中失败。它假设的东西不在语言规范中。但是,这不是完整的副本。此代码使用不安全的方式访问所有片中常见的SliceHeader。标题包含一个指向数据(C数组)的长度和容量的指针。我们首先需要改变长度和容量,而不是仅仅将头部转换为新的分片类型,因为如果将字节视为新类型,那么我们需要更改元素的数量。

 import(
反映
不安全


const SIZEOF_INT32 = 4 //字节

//获取切片头
头:= *(* reflect.SliceHeader)(unsafe.Pointer(& raw))

//长度和容量切片是不同的。
header.Len / = SIZEOF_INT32
header.Cap / = SIZEOF_INT32

//将切片头转换为[] int32
data:= *(* [] int32)(unsafe.Pointer(& header))


I get a byte slice ([]byte) from a UDP socket and want to treat it as an integer slice ([]int32) without changing the underlying array, and vice versa. In C(++) I would just cast between pointer types; how would I do this in Go?

解决方案

As others have said, casting the pointer is considered bad form in Go. Here are examples of the proper Go way and the equivalent of the C array casting.

WARNING: all code untested.

The Right Way

In this example, we are using the encoding/binary package to convert each set of 4 bytes into an int32. This is better because we are specifying the endianness. We are also not using the unsafe package to break the type system.

import "encoding/binary"

const SIZEOF_INT32 = 4 // bytes

data := make([]int32, len(raw)/SIZEOF_INT32)
for i := range data {
    // assuming little endian
    data[i] = int32(binary.LittleEndian.Uint32(raw[i*SIZEOF_INT32:(i+1)*SIZEOF_INT32]))
}

The Wrong Way (C array casting)

In this example, we are telling Go to ignore the type system. This is not a good idea because it may fail in another implementation of Go. It is assuming things not in the language specification. However, this one does not do a full copy. This code uses unsafe to access the "SliceHeader" which is common in all slices. The header contains a pointer to the data (C array), the length, and the capacity. Instead of just converting the header to the new slice type, we first need to change the length and capacity since there are less elements if we treat the bytes as a new type.

import (
    "reflect"
    "unsafe"
)

const SIZEOF_INT32 = 4 // bytes

// Get the slice header
header := *(*reflect.SliceHeader)(unsafe.Pointer(&raw))

// The length and capacity of the slice are different.
header.Len /= SIZEOF_INT32
header.Cap /= SIZEOF_INT32

// Convert slice header to an []int32
data := *(*[]int32)(unsafe.Pointer(&header))

这篇关于在不同类型的切片之间转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆