Указатель и функция-член структуры

#go

#Вперед

Вопрос:

Вызов функции

Когда я определяю структуру Lock и функцию Test со структурой Lock в качестве получателя функции

 type Lock struct {
}

func (self Lock) Test() {
    fmt.Println("Test Func")
}
  

Я обнаружил, что могу вызвать эту функцию с помощью структурного указателя Lock

 lock := amp;Lock{}
lock.Test()
  

То же самое, если я определяю структуру Lock и функцию Test в качестве Lock указателя в качестве получателя, я могу вызвать эту функцию через Lock экземпляр struct .

Итак, каким бы получателем ни была сама структура или указатель на структуру, я могу вызвать эту функцию через оба? В чем причина. Насколько я понимаю, struct и указатель struct — это совершенно два разных типа!

Интерфейс

Если определить интерфейс Locker , подобный этому

 type Locker interface {
    Test()
}
  

И определите структуру Lock и функцию Test с экземпляром struct в качестве получателя, я не могу назначить переменную указателя Locker структуры переменной интерфейса.

Напротив, если a определяет структуру Lock и функцию Test с указателем структуры в качестве получателя, присвоение переменной экземпляра структуры переменной Locker интерфейса может работать!

Я так смущен дизайном языка. Кто-нибудь может дать мне несколько советов?

Комментарии:

1. Вы ищете правила для селекторов

2. И взгляните на спецификацию языка в целом, особенно на разделы набора методов. И, конечно же: совершите экскурсию по Go еще раз.

Ответ №1:

Обычно Go делает что-то для вас под капотом, и это, как правило, один из таких случаев.

Когда вы определяете функцию со структурой в качестве получателя и передаете ей указатель на структуру, Go выполняет преобразование за вас: он передает копию структуры, на которую указывает.

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

Однако при определении интерфейса вы работаете с типами: Locker интерфейс определяет тип, который реализует функцию Test() .

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

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

Комментарии:

1. Не совсем точно. Go все еще выполняет небольшое преобразование для интерфейсов. Правило состоит в том, что если вы передаете указатель на тип в интерфейс, методы указателя и значения для этого типа могут выполнять интерфейс. Если вы передаете сам тип, только методы значений для этого типа могут выполнять интерфейс. Пример: play.golang.org/p/rUIeMBnXTY

2. Спасибо за ваш ответ! Это действительно помогает мне разобраться в этом.