В чем разница между func foo(arr []int) int и func foo(arr [num]int) int
В чем разница между func foo(arr []int) int
а также func foo(arr [*num*]int) int
?
Вот два примера:
func foo1(arr [2]int) int {
arr[0] = 1
return 0
}
func foo2(arr []int) int {
arr[0] = 1
return 0
}
func main() {
var arr1 = [2]int{3, 4}
var arr2 = []int{3, 4}
foo1(arr1)
println(arr1[0]) // result is 3, so arr in foo1(arr) is a copy
foo2(arr2)
println(arr2[0]) // result is 1, so arr in foo2(arr) is not a copy, it is a reference
}
Я также нашел, если я использую foo1(arr2)
или же foo2(arr1)
, компилятор сообщит об ошибке типа "не может использовать arr2 (type []int) в качестве типа [2]int в аргументе для foo1" и "не может использовать arr1 (type [2]int) в качестве типа [] int в аргументе для foo2" "
Так кто же может помочь объяснить, в чем разница между ними, или дать мне ссылку на учебу? Заранее спасибо.
3 ответа
[2]int
это массив, []int
это кусочек.
Массивы и срезы совершенно разных типов: вы не можете передать массив, где требуется срез, и вы не можете передать срез, где ожидается массив. Поскольку длина является частью типа массива, вы даже не можете использовать значения массива там, где длина отличается, например, вы не можете использовать значение массива типа [3]int
за то, что ожидает [2]int
,
Все в Go передается по значению. Ломтики тоже. Но значение среза является заголовком, описывающим непрерывный раздел резервного массива, а значение среза содержит только указатель на массив, где элементы фактически сохранены. Значение среза не включает его элементы (в отличие от массивов). Когда вы передаете срез, копируется только заголовок среза (указывающий на один и тот же резервный массив), поэтому изменение его элементов приводит к изменению элементов в одном и том же базовом массиве, поэтому вызывающая сторона будет наблюдать за изменениями. Подробнее об этом здесь: передаются ли кусочки голанга по значению? Чтобы увидеть, что находится в заголовке фрагмента: reflect.SliceHeader
,
В отличие от слайсов, массивы не являются заголовками. Значение массива означает все его элементы, поэтому, когда вы передаете значение массива, все его элементы копируются, и внутри функции, которой оно передается, вы можете только изменить этот массив копирования; вызывающая сторона не будет наблюдать за изменениями, внесенными в массив (например, изменение его элементов).
Обратите внимание, что, однако, очень просто получить значение среза из массива, вы можете просто использовать нарезку:
var a [2]int = [2]int{1, 2}
var s []int = a[:]
fmt.Println(s) // Prints [1 2]
Рекомендуемое сообщение в блоге: Go Slices: использование и внутреннее оборудование
Более глубокое понимание массивов и фрагментов: почему массивы в Go?
[2]int
является массивом фиксированной длины с 2 записями.[]int
нефиксированный срез
func foo1(arr [2]int)
ожидает массив int фиксированной длины с 2 записями.func foo2(arr []int)
принимает нефиксированный фрагмент int с любым количеством записей.
Они похожи, но это может помочь, если вы думаете о [2]int и []int как о совершенно разных структурах.
Тип [n]T
это массив n
значения типа T
,
Тип []T
срез с элементами типа T
,
Массив имеет фиксированный размер. тогда как срез является динамическим.
С foo1
копия массива производится при вызове функции.
Так что первоначальная стоимость arr1
остается неизменной