Подтвердить что ты не робот

Неявно передаются ли каналы по ссылке

В этом туре есть этот пример для каналов: http://tour.golang.org/#63

package main

import "fmt"

func sum(a []int, c chan int) {
    sum := 0
    for _, v := range a {
        sum += v
    }
    c <- sum // send sum to c
}

func main() {
    a := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(a[:len(a)/2], c)
    go sum(a[len(a)/2:], c)
    x, y := <-c, <-c // receive from c

    fmt.Println(x, y, x+y)
}

Канал c изменяется в функции суммы, и изменения сохраняются после завершения функции. Очевидно, c был передан по ссылке, но указатель на c не был создан. Являются ли каналы неявно переданы по ссылке в go?

4b9b3361

Ответ 1

Технически они копируются, потому что, когда вы используете make, вы выделяете что-то в куче, так что это технически указатель за кулисами. Но тип указателя не отображается, поэтому их можно рассматривать как ссылочный тип.

ИЗМЕНИТЬ: Из спецификации:

Встроенная функция make принимает тип T, который должен быть типом среза, карты или канала, необязательно сопровождаемым списком выражений типа. Он возвращает значение типа T (not * T). Память инициализируется, как описано в разделе, посвященном начальным значениям.

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

В основном это означает, что вы можете передать его в функцию и написать или прочитать из нее. Общее правило: если вы используете make, new или &, вы можете передать его другой функции без копирования базовых данных.

Итак, следующие типы ссылок:

  • ломтика
  • карты
  • Каналы
  • Указатели
  • Функции

При переходе в функцию копируются только типы данных (числа, bools и structs и т.д.). Строки являются особыми, потому что они неизменяемы, но не передаются по значению. Это означает, что следующее не будет работать, как ожидалось:

type A struct {
    b int
}
func f(a A) {
    a.b = 3
}
func main() {
    s := A{}
    f(s)
    println(s.b) // prints 0
}

Ответ 2

Все в Go передается и присваивается значением. Некоторые встроенные типы, включая типы каналов и типы карт, ведут себя как непрозрачные указатели на некоторую скрытую внутреннюю структуру. И эту внутреннюю структуру можно изменить с помощью операций на канале или карте. Они начинаются как nil, что аналогично указателю nil.

Ответ 3

Можно сказать "да", но сказать, что "канал c изменен в функции суммы" на самом деле не является правильной терминологией. Отправки и прием каналов на самом деле не считаются изменениями.

Обратите внимание, что так, как показано на слайках и картах, см. http://golang.org/doc/effective_go.html для более подробной информации.

Также "переданный по ссылке" подразумевает, что присваивание может быть выполнено в c в sum, что изменило бы его значение (в отличие от его базовых данных) вне суммы, что не так.

Ответ 4

Канальные переменные являются ссылками, но это зависит от вашего определения "reference". Спецификация языка никогда не упоминает ссылочные типы.

Никакой канал (переменная) не изменен в функции sum. Отправка на канал изменяет его состояние.

Другими словами, да, канал реализуется как указатель на некоторую структуру времени выполнения. Обратите внимание, что это строго необходимо для эталонной семантики.

EDIT: приведенное выше предложение предназначено для чтения: "Обратите внимание, что это не является строго необходимым для эталонной семантики", т.е. слово "не" пошло в МВД. Извините за возникшую путаницу.