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

В Go называет переменную "self" приемника "вводящей в заблуждение" или хорошую практику?

Я видел большое количество блогов и видео на Go, и, насколько я помню, ни один из авторов не использовал "self" или 'this' для переменной получателя при написании методов. Однако, похоже, существует ряд вопросов о переполнении стека, и это заставило меня задуматься о том, вводит ли это в заблуждение имя переменной "я"?

Чтение Spec для Наборы методов не дает никаких доказательств в любом случае (в моей интерпретации).

Кажется, я нахожу, что нахожусь где-то в другом месте, что он не является самонаучным указателем, может ли кто-нибудь перечислить доказательства или дать аргументацию в любом случае, и если возникнут какие-либо проблемы/ловушки, которые могут возникнуть из-за того, что они воспринимают его как "я"?

Быстрый пример:

type MyStruct struct {
    Name string
} 

Какой метод более уместен или оба?

func (m *MyStruct) MyMethod() error {
    // do something useful
}

или

func (self *MyStruct) MyMethod() error {
    // do something useful
}
4b9b3361

Ответ 1

В дополнение к тому, что говорили другие (особенно PeterSO и dskinner — в своем комментарии к ответу Питера), обратите внимание на несколько важных вещей:

Вы можете вызвать метод, как простая функция

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

Чтобы продемонстрировать:

package main

import "fmt"

type Foo int

func (f Foo) Bar() {
    fmt.Printf("My receiver is %v\n", f)
}

func main() {
    a := Foo(46)
    a.Bar()
    b := Foo(51)
    Foo.Bar(b)
}

(ссылка для игровой площадки.

При запуске эта программа печатает:

My receiver is 46
My receiver is 51

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

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

Приемник не обязательно может изменяться внутри метода, определенного в его типе

Как показано в моем примере, я определил метод Bar() на приемнике не указателя, и если вы попытаетесь присвоить значение получателю, которое будет успешным, но не повлияет на вызывающего абонента потому что приемник, поскольку все в Go — передано по значению (так что целое только что было скопировано).

Чтобы иметь возможность мутировать значение получателя в методе, вам нужно определить его на соответствующем вводе указателя, например

func (f *Foo) Bar() {
    // here you can mutate the value via *f, like
    *f = 73
}

Опять же, вы можете видеть, что с помощью self, что означает "я", "мои внутренности" становятся спорными: в моем примере метод просто получил значение, которое он знает. Вы можете видеть, что это контрастирует со многими OO-языками, в которых объектом является черный ящик, обычно проходящий по ссылке. В Go вы можете определить метод практически для любого (включая другие методы, который используется стандартным пакетом net/http, кстати) который разрушает концепцию "методы для объектов".

Различные наборы методов могут быть применимы к одному и тому же значению в разное время

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

Хорошим примером этого является стандартный пакет sort: например, он предоставляет тип IntSlice, который позволяет сортировать кусок целых чисел - значение типа []int. Для этого вы набираете текст в виде sort.IntSlice и значение, которое вы получаете в результате, имеет целый набор методов для сортировки вашего среза, в то время как внутреннее представление вашего значения не изменилось — потому что sort.IntSlice определяется как type IntSlice []int. В каждом методе этого типа IntSlice трудно согласовать значение их значения приемника с self — просто потому, что тип существует только для предоставления набора методов для другого типа; в философском смысле такие типы полезности не имеют понятия "я"; -)

Заключение

Итак, я бы сказал, держите вещи в голове и не пытайтесь "перегружать" ясный и простой подход, взятый Go с семантикой, в котором он явно не указывает, что он предоставляет.

Еще одно примечание. Мое личное восприятие Идиомы Go, когда я их узнал, заключается в том, что первостепенное свойство Go - это его практичность (в отличие от идеализма и т.д.), Поэтому, если вы видите какое-то понятие, которое "чувствует" неестественное, попытайтесь понять, почему оно было разработано именно так, и большинство часто вы обнаружите, почему концепция "щелкает" в вашем мозгу и становится естественной. (Должен признаться, что для того, чтобы понять эту конкретную проблему с методами понимания в Go, хорошее знакомство с C было бы очень полезно.)

Ответ 3

Посмотрите исходный код команд Go и выберите стандартные пакеты для примеров хорошего стиля программирования. Имя self не используется для приемников метода Go.

Перейти к исходному коду

Имя self - это соглашение Python. Go не является Python.

Учебник Python

9.4. Случайные замечания

Часто первый аргумент метода называется self. Это ничего более чем конвенция: имя "я" абсолютно не имеет специального что означает Python. Обратите внимание, однако, что, не соблюдая конвенцию ваш код может быть менее читаемым для других программистов на Python, и это также можно предположить, что программа браузера классов может быть написана так: опирается на такое соглашение.

Ответ 4

Я не вижу особого основания избегать соглашения this/self. Другие сообщения здесь просто приводят в соответствие с нормами сообщества или описывают аспекты отправки метода, которые не имеют отношения к соглашениям об именах.

Эти рекомендации по обзору кода отклоняют this или self без каких-либо оснований, если вы не можете прочитать что-то в подразумеваемой претензии которые придают меньше внимания методам, чем другие языки.

Одно из преимуществ совершения соглашения this или self заключается в том, что оно помогает выявить нарушения Закона Деметры. Код, например:

func (w *ChunkWriter) Write(recId uint32, msg []byte) (recs uint64, err error) {
    recs = w.chunk.Records
    err = w.handle.Write(recId, msg)
    if err == nil {
        recs++
        w.chunk.Records = recs
    }
    return
}

появляется на лице, чтобы оно не попадало в члены w. Фактически, он обращается к членам своего приемника, что совершенно правильно.