Разница между методами подписи структур - PullRequest
0 голосов
/ 11 декабря 2018

Как программист, пришедший из других языков, таких как C ++, я нахожу довольно странным, что go позволяет указывать методы для структур, которые допускают указатель или экземпляр в качестве параметра.Согласно go на примере однажды мог бы использовать любой из них, если мы не хотели изменять источник:

Go автоматически обрабатывает преобразование между значениями и указателями для вызовов методов.Возможно, вы захотите использовать указатель типа получателя, чтобы избежать копирования при вызове метода или разрешить методу изменять структуру получателя.

Рассмотрите следующий код:

package main

import (
    "fmt"
)

type Foo struct {}

type Bar struct {}

func (this Foo) String() string {
  return "Foo"
}

func (this *Bar) String() string {
  return "Bar"
}

func main() {
  fmt.Println(Foo{}) // "Foo"
  fmt.Println(Bar{}) // "{}"
}

Почемуя не могу использовать обе версии подписи для изменения stringify (я не знаю, как это на самом деле называется in go) поведения структур?

Просто чтобы прояснить: я не понимаюдействительно не заботится о stringify, но хочет понять, как ведет себя язык.

Ответы [ 2 ]

0 голосов
/ 11 декабря 2018

Потому что Bar не реализует stringify * Bar делает.

Если вы удалите реализацию stringify из Foo, вы получите «{}».

Аналогично, когда вы пишете fmt.Println(Bar{}), это означает, что оно будет выглядеть примерно так: func (Bar) String()и не func (*Bar) String()

Additioanlly, история отличается, когда вы пишете fmt.Println(&Foo{}), вы можете подумать, что она напечатает «{}», потому что нет func (*Foo) String(), но она напечатает «Foo».

Для этого вам придется понимать интерфейсы.Это мой опыт, поэтому, пожалуйста, проведите собственное исследование тоже.Функция fmt.Print использует String () из stringify.Таким образом, на самом деле String () вызывается не для вашей структуры, а для переменной типа stringify.

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

может содержать указатель типа (который его реализовал), только если он был реализован с помощью приемника указателя.Зачем?Потому что, когда вы реализуете интерфейс с указателем приемника, ему нужен адрес, который может быть предоставлен только с указателем.Вот почему работает только &Bar{}, а не Bar{}

0 голосов
/ 11 декабря 2018

Просто добавьте & к Bar{} и сделайте его получателем указателя, например:

fmt.Println(&Bar{}) // "Bar"

Вот небольшая настройка для вашего кода, который выводит:

Foo
Bar

см .:

package main

import "fmt"

type Foo struct{}

func (Foo) String() string {
    return "Foo"
}

type Bar struct{}

func (*Bar) String() string {
    return "Bar"
}

func main() {
    fmt.Println(Foo{}) // "Foo"
    pb := &Bar{}
    fmt.Println(pb) // "Bar"
}

Примечания:

Имя получателя должно отражать его идентичность;не используйте общие имена, такие как «this» или «self»

И вам не нужны здесь имена для вашего примера.

И приятно читать Golangметоды приемников :

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...