Golang中如何获取数组/切片的实际字节大小

Golang中如何获取数组/切片的实际字节大小 我正在尝试实现基础列表操作,而不使用像len()这样的内置方法。但我找不到获取切片/数组字节大小的方法来实现length()函数。

我尝试过unsafe.Sizeof()方法,但根据文档,它只给出切片描述符的大小,而不是切片引用的内存大小。

type IntList []int

func main() {
    list := IntList{1, 2, 3, 4}
    list.Length() // 期望结果 - 4
}

// 假设int类型包含4个字节
func (l IntList) Length() int {
    size := actualByteSize(l) / 4 
    return int(size)
}

我是Go语言的新手。😊


更多关于Golang中如何获取数组/切片的实际字节大小的实战教程也可以访问 https://www.itying.com/category-94-b0.html

8 回复

可能与以下代码相同:

func (list *IntList) Length() int {
	return len(*list)
}

更多关于Golang中如何获取数组/切片的实际字节大小的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


谢谢!但正如我提到的,我想在不使用内置长度函数的情况下获取数组的长度。

您的回答似乎没有完整送达。请重新发送一次… 在此期间,您可以查阅 https://blog.golang.org/go-slices-usage-and-internals

我想在不使用相关内置方法的情况下实现这个功能,因为我知道常规方法是:

byteSize(intArray) / size_of_int

我想知道在 Go 中是否有任何方法可以实现这一点。

在这种情况下,您可以使用 encoding/binary 包和 Size 函数,例如
https://play.golang.org/p/HhJif66VwY

package main

import (
	"encoding/binary"
	"fmt"
)

func main() {
	var i int
	fmt.Println(binary.Size(i))
}

不,正如我在示例代码中提到的,是指整数数组的长度。

list := IntList{1, 2, 3, 4}
list.Length() // 预期结果 - 4

我想在不知道该特定数组中元素数量的情况下获取此数组的字节大小。实际上我只是想重新实现内置的len()方法(听起来可能有点傻😄但我只是想尝试一下)

切片实际上是一个类似这样的结构体:

struct {
   address to array
   len int
   cap int
}

因此,不使用len()获取长度可以这样实现:

package main

import (
	"fmt"
	"unsafe"
)

type slice struct {
	ptr uintptr
	len int
	cap int
}

func main() {
	someSlice := make([]byte, 666)

	fmt.Println((*slice)(unsafe.Pointer(&someSlice)).len)

}

在Go语言中,要获取切片或数组的实际字节大小,确实不能直接使用unsafe.Sizeof(),因为它只返回类型描述符的大小。对于切片,你需要计算切片底层数组的字节大小。

以下是几种实现方式:

方法1:使用反射获取切片长度和元素大小

package main

import (
    "fmt"
    "reflect"
    "unsafe"
)

type IntList []int

func (l IntList) Length() int {
    if len(l) == 0 {
        return 0
    }
    
    // 获取切片头信息
    sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&l))
    
    // 计算实际字节大小
    elemSize := int(unsafe.Sizeof(l[0]))
    actualByteSize := sliceHeader.Len * elemSize
    
    // 返回元素个数
    return sliceHeader.Len
}

// 单独获取字节大小的函数
func (l IntList) ActualByteSize() int {
    if len(l) == 0 {
        return 0
    }
    sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&l))
    elemSize := int(unsafe.Sizeof(l[0]))
    return sliceHeader.Len * elemSize
}

func main() {
    list := IntList{1, 2, 3, 4}
    fmt.Printf("Length: %d\n", list.Length())           // 输出: Length: 4
    fmt.Printf("Byte Size: %d\n", list.ActualByteSize()) // 输出: Byte Size: 32 (在64位系统上)
}

方法2:更简洁的实现(推荐)

package main

import (
    "fmt"
    "unsafe"
)

type IntList []int

func (l IntList) Length() int {
    if len(l) == 0 {
        return 0
    }
    
    // 直接计算元素个数
    slicePtr := unsafe.Pointer(&l[0])
    elemSize := unsafe.Sizeof(l[0])
    
    // 获取切片容量信息(可选)
    var dummy []int
    sliceHeaderSize := unsafe.Sizeof(dummy)
    _ = sliceHeaderSize // 切片头大小,通常为24字节(64位系统)
    
    return len(l) // 实际上可以直接用len()
}

// 获取实际字节大小
func (l IntList) ByteSize() int {
    return len(l) * int(unsafe.Sizeof(l[0]))
}

func main() {
    list := IntList{1, 2, 3, 4, 5}
    fmt.Printf("Length: %d\n", list.Length())    // 输出: Length: 5
    fmt.Printf("Byte Size: %d\n", list.ByteSize()) // 输出: Byte Size: 40
}

方法3:通用实现(适用于任何类型)

package main

import (
    "fmt"
    "unsafe"
)

type List[T any] []T

func (l List[T]) Length() int {
    return len(l)
}

func (l List[T]) ByteSize() int {
    if len(l) == 0 {
        return 0
    }
    var zero T
    elemSize := int(unsafe.Sizeof(zero))
    return len(l) * elemSize
}

func main() {
    intList := List[int]{1, 2, 3, 4}
    stringList := List[string]{"a", "b", "c"}
    
    fmt.Printf("Int List - Length: %d, Byte Size: %d\n", 
        intList.Length(), intList.ByteSize())
    fmt.Printf("String List - Length: %d, Byte Size: %d\n", 
        stringList.Length(), stringList.ByteSize())
}

重要说明:

  1. unsafe.Sizeof() 返回的是类型的大小,不是切片内容的大小
  2. 切片结构包含:指向底层数组的指针、长度、容量
  3. 实际需求:对于列表操作练习,你通常只需要元素个数(长度),而不是字节大小

对于你的列表操作实现,建议直接使用len()函数,或者如果练习要求不使用内置函数,可以通过遍历切片来计算长度:

func (l IntList) Length() int {
    count := 0
    for range l {
        count++
    }
    return count
}

这样更符合练习的目的,且不需要使用unsafe包。

回到顶部