In go, обратно совместимо изменить структуру получателя со значения на указатель?

Начиная с кода вроде:

type Foo struct {
    V bool
}

func (f Foo) bar() bool {
    return f.V
}

Можно ли изменить на func (f *Foo) bar() bool без увеличения основного номера версии? То есть, если вы знаете, что с вашим типом нет проблем с безопасностью потоков. Если да, то обратное изменение тоже разрешено, верно?

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

это отвечает на ваш вопрос?. Вот пример, который ломается при изменении.

Brits 21.07.2023 07:05

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

Fsmv 21.07.2023 08:18

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

Fsmv 21.07.2023 08:19

@Британцы, не могли бы вы добавить это ответ, чтобы я мог его принять?

Fsmv 22.07.2023 02:18
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
3
4
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Если для типа Foo у вас есть метод с приемником значения:

func (f Foo) Method() {...}

Затем этот метод определяется как для Foo, так и для *Foo, и в обоих случаях метод получает копию экземпляра Foo. Если вы измените это на:

func (f *Foo) Method() {...}

тогда Foo.Method доступен только для *Foo, а не для Foo. Таким образом, такое изменение может вызвать ошибки компиляции.

Если у вас есть метод, объявленный с приемником указателя, и теперь вы меняете его на приемник значения, вы объявляете метод как для Foo, так и для *Foo, поэтому у вас не должно быть ошибок компиляции. Семантика метода также изменится, потому что теперь Method будет получать копию экземпляра Foo, даже если этот экземпляр адресный или является указателем.

Я протестировал его, и он компилируется для использования переменной-указателя с получателем значения: go.dev/play/p/pKwO7oA39w7 Я думал, что это не сработает, пока тоже не проверил!

Fsmv 21.07.2023 05:17
Ответ принят как подходящий

Согласно комментариям, этот ответ дает хорошее резюме T и *T типов получателей. Ниже приведено несколько примеров, когда изменение с func (f Foo) bar() bool на func (f *Foo) bar() bool нарушило бы существующий код.

Пример 1: T не адресуется (детская площадка):

type Foo struct {
    V bool
}

func (f *Foo) bar() bool { // Change to `(f Foo)` and this will work
    return f.V
}

func x() Foo {
    return Foo{true}
}

func main() {
    fmt.Printf("%v", x().bar())
}

Пример 2: Интерфейс (детская площадка):

type Foo struct {
    V bool
}

func (f *Foo) bar() bool { // Change to `(f Foo)` and this will work
    return f.V
}

type Fooer interface {
    bar() bool
}

func main() {
    var x Fooer
    x = Foo{}
    fmt.Println(x.bar())
}

Другие вопросы по теме