Массивы в Go по значению? - PullRequest
0 голосов
/ 05 июля 2018
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]
}

При выполнении теста сверху кажется, что массивы в Go передаются по значению, а не по ссылке. Итак, могу ли я заключить, что нет необходимости в понятиях shallow-copying и deep-copying, необходимых для работы с таким веществом в Go?

Ответы [ 3 ]

0 голосов
/ 05 июля 2018

Спецификация языка программирования Go

Типы массивов

Массив - это пронумерованная последовательность элементов одного типа, называемая тип элемента. Количество элементов называется длиной и составляет никогда не бывает отрицательным

Длина является частью типа массива; это должно оценить неотрицательная константа, представимая значением типа int. Длина массива а можно обнаружить с помощью встроенной функции len. элементы могут быть адресованы целочисленными индексами от 0 до len (a) -1.

Типы срезов

Срез - это дескриптор непрерывного сегмента базового массив и обеспечивает доступ к пронумерованной последовательности элементов из этого массив. Тип среза обозначает набор всех срезов массивов его тип элемента. Значение неинициализированного среза равно нулю.

Как и массивы, срезы индексируются и имеют длину. Длина срез s может быть обнаружен встроенной функцией len; в отличие от массивы это может измениться во время выполнения. Элементы могут быть адресованы по целочисленным индексам от 0 до len (s) -1. Индекс среза данного элемент может быть меньше, чем индекс того же элемента в базовый массив.

Срез после инициализации всегда связан с базовым массив, который содержит свои элементы. Поэтому срез разделяет хранилище с его массив и с другими срезами того же массива; напротив, Отдельные массивы всегда представляют отдельное хранилище.

Массив, лежащий в основе слайса, может простираться за конец слайса. емкость является мерой этой степени: это сумма длины срез и длина массива за срезом; ломтик Длина до этой емкости может быть создана путем нарезки нового из оригинальный срез. Емкость среза можно определить с помощью встроенная функция крышки (а).


Вы должны сравнить массивы Go с фрагментами Go. Назначение копирует значение массива. Назначение копирует значение дескриптора среза. Дескриптор слайса - это структура с длиной, емкостью и указателем на базовый массив слайсов.

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

Например,

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)
}

Детская площадка: https://play.golang.org/p/8eFa1Mod_Kj

Выход:

[1 2 3 4 5] [1 2 3 4 100]
[1 2 3 4 100] [1 2 3 4 100]
0 голосов
/ 05 июля 2018

Все в Go передается по значению (в Go нет понятия «передача по ссылке»).

Поскольку все передается по значению, оно копируется. Копия указателя - это просто копия адреса, а не «глубокая копия». Таким образом, копия объекта без прямых или скрытых указателей будет глубокой копией, а копия чего-либо с явным или неявным указателем будет поверхностной копией.

Массивы не содержат указателей, поэтому, если у ваших элементов Array нет, вы получите глубокую копию.

Срезы, каналы и карты do содержат (скрытые) указатели, и их копирование даст вам копию фрагмента (канала, карты), но мелкого: содержимое внутри не будет скопировано как они не являются прямой частью среза (срез содержит указатель на фактические данные).

Так что в Go есть понятие глубокой и мелкой копии. Грубо говоря: все копируется глубоко, а глубокая копия указателя - это просто копия адреса (не указателя): глубокое копирование останавливается на указателях (даже скрытых, встроенных в язык, как в слайсах).

Как обычно, довольно очевидно и детерминировано, что копируется, когда указатели явны в Go.

0 голосов
/ 05 июля 2018

все в Go всегда передается по значению, даже с указателем, он копирует 8 байтов этого указателя.

...