> For the complete documentation index, see [llms.txt](https://joyous-x.gitbook.io/mbook/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://joyous-x.gitbook.io/mbook/part-i-language/catalog-1/slice_base.md).

# slice 底层结构

## Summary

Go 中数组赋值和函数传参都是值复制的, 切片是引用传递

* 数组
  * 初始化时指定长度，如：

    ```
      a := [2]int{1,2}
      var b [2]int
    ```
* 切片(slice)
  * 是对数组一个连续片段的引用，所以切片是一个引用类型 (因此更类似于 C/C++ 中的数组类型，或者 Python 中的 list 类型)
  * 初始化时不指定长度，如：

    ```
      a := []int{1,2}
      var b []int
    ```

## Defination

Slice 的数据结构定义如下:

```
    // runtime/slice.go
    type slice struct {
        array unsafe.Pointer
        len   int
        cap   int
    }
```

如果想从 slice 中得到一块内存地址，可以这样做：

```
    s := make([]byte, 10)defination
    ptr := unsafe.Pointer(&s[0])
```

如果反过来呢？从 Go 的内存地址中构造一个 slice。

```
    var ptr unsafe.Pointer
    var tmp = struct {
        addr uintptr
        len int
        cap int
    }{ptr, length, length}
    s := *(*[]byte)(unsafe.Pointer(&tmp))
```

构造一个虚拟的结构体，把 slice 的数据结构拼出来。

当然还有更加直接的方法，在 Go 的反射中就存在一个与之对应的数据结构 SliceHeader，我们可以用它来构造一个 slice

```
    var o []byte
    sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&o)))
    sliceHeader.Cap = length
    sliceHeader.Len = length
    sliceHeader.Data = uintptr(ptr)
```

## nil切片 和 空切片

nil切片

```
    // 内存布局：
    //    Slice ---> nil | Len = 0 | Cap = 0
    var slice []int
```

空切片

```
    // 内存布局：
    //     Slice ---> Pointer to Array | Len = 0 | Cap = 0
    silce := make( []int , 0 )
    slice := []int{ }
```
