Является ли unnamed аргументом вещь в Go?

Я пишу парсер в Go for Go, и для его проверки я загрузил кучу файлов из проектов github.
В https://github.com/andlabs/ui я столкнулся с файлом, содержащим этот фрагмент кода:

func moveLabel(*Button) {
    from := movingCurrent
    to := 0
    if from == 0 {
        to = 1
    }
    movingBoxes[from].Delete(0)
    movingBoxes[to].Append(movingLabel, false)
    movingCurrent = to
}

Это немного путает меня, чтобы увидеть указатель на Button без имени в качестве аргумента функции, что делает невозможным ссылку изнутри функции.
Однако он кажется синтаксически правильным, учитывая, что компилятор не жалуется.
Какова цель аргументов неименованных функций в Go?

Ответ 1

Безымянные параметры являются абсолютно действительными. Объявление параметров из спецификации:

ParameterDecl  = [ IdentifierList ] [ "..." ] Type .

Как видите, IdentifierList (имя или имена идентификаторов) заключены в квадратные скобки, что означает его необязательность. Требуется только Type.

Причина этого в том, что имена не очень важны для тех, кто вызывает метод или функцию. Важны типы параметров и их порядок. Это подробно описано в этом ответе: Получение имен параметров метода в Golang

Обычно вы называете переменные и параметры, чтобы вы могли ссылаться на них.

Когда вы что-то не называете, это потому, что вы не хотите на него ссылаться.

Поэтому вопрос должен быть: почему бы мне не захотеть ссылаться на параметр?

Например, поскольку параметр "есть" (он передается), но он вам не нужен, вы не хотите его использовать. Зачем это там, если мне это не нужно?

Потому что кто-то или что-то диктует наличие определенных параметров. Например, вы хотите реализовать интерфейс или передать значение функции, сигнатура которой определяется ожидаемым типом функции.

Давай посмотрим пример. У нас есть следующий интерфейс MyWriter:

type MyWriter interface {
    Write(p []byte) error
}

Упрощенный io.Writer, который только возвращает ошибку, но не сообщает о количестве записанных байтов. Если вы хотите предоставить реализацию, которая просто отбрасывает данные (аналогично ioutil.Discard), тогда реализация не использует (не нуждается в использовании) свой аргумент:

type DiscardWriter struct{}

func (DiscardWriter) Write([]byte) error { return nil }

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

Это (с использованием неназванных параметров) также документирует, что значение не используется/не упоминается.

Другой причиной может быть обеспечение прямой совместимости. Если вы освобождаете библиотеку, вы не можете изменять или расширять список параметров, не нарушая обратную совместимость (а в Go нет перегрузки функций: если вы хотите 2 варианта с разными параметрами, их имена также должны отличаться). Таким образом, вы можете объявить экспортированную функцию или метод с дополнительными параметрами заранее, но так как вы еще не используете их, вы можете оставить их без имени. Пример этого подробно описан в этом ответе: Почему Go позволяет компилировать неиспользуемые параметры функции?

Здесь следует отметить, что нельзя смешивать именованные и безымянные параметры. Если вы называете некоторые, вы должны назвать все. Если вам не нужно все, вы можете использовать пустой идентификатор, как в этом примере:

Простой веб-сервер, который отвечает текстом "Hello" на все запросы:

http.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
    io.WriteString(w, "Hello")
})
panic(http.ListenAndServe(":8080", nil))

Функция-обработчик, отправляющая обратно текст "Hello", использует только средство записи ответов w, но не структуру запроса, поэтому в качестве имени используется пустой идентификатор.

Еще один связанный с этим вопрос:

Почему мы должны объявлять имя переменной при добавлении метода в структуру в Golang?

Также несколько связано, но относительно использования/именования возвращаемых значений:

Вернуть карту, как & # 39; ok & # 39; в Голанге о нормальных функциях

А что касается получения имен параметров метода/функции:

Получение имен параметров метода в Golang

Ответ 2

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

Посмотрите этот пример на странице "Effective Go" на golang.org. https://golang.org/doc/effective_go.html#named-results

func ReadFull(r Reader, buf []byte) (n int, err error) {
    for len(buf) > 0 && err == nil {
        var nr int
        nr, err = r.Read(buf)
        n += nr
        buf = buf[nr:]
    }
    return
}