Go中的数组是按值计算的吗?

package main

import (
  "fmt"
)

func main() {
  var a = [5]int{1,2,3,4,5}
  b := a
  b[4] = 100
  fmt.Println(a,b) //[1 2 3 4 5] [1 2 3 4 100]
}

Doing a test from above, it seems that arrays in Go are passed by value instead of reference. So can I conclude that there is no concept of shallow-copying nor deep-copying needed when dealing with such matter in Go?

The Go Programming Language Specification

Array types

An array is a numbered sequence of elements of a single type, called the element type. The number of elements is called the length and is never negative.

The length is part of the array's type; it must evaluate to a non-negative constant representable by a value of type int. The length of array a can be discovered using the built-in function len. The elements can be addressed by integer indices 0 through len(a)-1.

Slice types

A slice is a descriptor for a contiguous segment of an underlying array and provides access to a numbered sequence of elements from that array. A slice type denotes the set of all slices of arrays of its element type. The value of an uninitialized slice is nil.

Like arrays, slices are indexable and have a length. The length of a slice s can be discovered by the built-in function len; unlike with arrays it may change during execution. The elements can be addressed by integer indices 0 through len(s)-1. The slice index of a given element may be less than the index of the same element in the underlying array.

A slice, once initialized, is always associated with an underlying array that holds its elements. A slice therefore shares storage with its array and with other slices of the same array; by contrast, distinct arrays always represent distinct storage.

The array underlying a slice may extend past the end of the slice. The capacity is a measure of that extent: it is the sum of the length of the slice and the length of the array beyond the slice; a slice of length up to that capacity can be created by slicing a new one from the original slice. The capacity of a slice a can be discovered using the built-in function cap(a).


You should compare Go arrays to Go slices. Assignment copies the array value. Assignment copies the slice descriptor value. The slice descriptor is a struct with a length, a capacity, and a pointer to its underlying slice array.

type slice struct {
    array unsafe.Pointer
    len   int
    cap   int
}

For example,

package main

import "fmt"

func main() {
    // array
    var a = [5]int{1, 2, 3, 4, 5}
    b := a
    b[4] = 100
    fmt.Println(a, b)

    // slice
    var s = []int{1, 2, 3, 4, 5}
    t := s
    t[4] = 100
    fmt.Println(s, t)
}

Playground: https://play.golang.org/p/8eFa1Mod_Kj

Output:

[1 2 3 4 5] [1 2 3 4 100]
[1 2 3 4 100] [1 2 3 4 100]

everything in Go always pass by value, even with pointer, it copies the 8 bytes of that pointer.

Everything in Go is passed by value (there is no notion of "pass by reference" in Go).

As everything is passed by value it is copied. A copy of a pointer is, well just a copy of the address and never a "deep copy". So a copy of an objects with no direct or hidden pointers will be a deep copy while a copy of something with an explicit or implicit pointer will be a shallow copy.

Arrays do not contain pointers, so if your Array elements do not you'll get a deep copy.

Slices and Channels and Maps do contain (hidden) pointers and copying them will give you a copy of the Slice (Channel, Map) but a shallow one: The stuff inside won't be copied as they are not a direct part of the Slice (the Slice contains a pointer to the actual data).

So there is a notion of deep and shallow copy in Go. Roughly: Everything is deep-copied and the deep-copy of a pointer is just a copy of the address (not the pointee): Deep-copying stops at pointers (even hidden ones built into the language like in Slices).

As usual it is pretty obvious and deterministic what gets copied when as pointers are explicit in Go.