Вопрос о приемнике с использованием struct in go

140
24

использование приемника

package main

import "fmt"

type Person struct {
name string
age int
}

func (p *Person) greeting1() {

fmt.Println(p) //&{0}
fmt.Println(&p) //0xc000086018
fmt.Println("Hello~")
}

func (p Person) greeting2() {
fmt.Println(p) //{0}
fmt.Println(&p) //&{0}
fmt.Println("Hello~")
}

type Student struct {
//p Persion -> has a
Person // -> is a
school string
grade int
}

func test1(p Student) {
fmt.Println(p)
}

func test2(p *Student){
fmt.Println(p)
}

func main() {
var s Student
//s.p.greeting()
s.greeting1()
s.greeting2()

test1(s)
//test2(s) -> error
}

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

a int= 10;
func func1(param int){
fmt.Println(fmt)
}

несмотря на то, что я объявил Person как структуру значений в структуре Student, как вы видите, мой код, функции приемника (приветствие1, приветствие2) получают два параметра типа: Person и Person. Я не могу понять, почему функция приветствия1 работает без ошибок, несмотря на то, что я поместил значение переменной в качестве параметра. Спасибо за помощь, ребята.

спросил(а) 2021-01-19T22:21:44+03:00 2 месяца, 3 недели назад
1
Решение
62

Упрощение вашего примера кода, чтобы сосредоточиться на вопросе/проблеме под рукой:

package main

import "fmt"

type Person struct {
name string
age int
}

func (p *Person) greeting1() {
fmt.Println(p)
fmt.Println(&p)
}

func main() {
var p Person
p.name = "joe"
p.age = 41
p.greeting1()
}

Печать:

&{joe 41}
0xc00000c028

Короче говоря, вызов p.greeting1() работает, потому что Go видит, что Person (типа p) имеет greeting1 метод, определенный на приемнике указателя. Таким образом, он обрабатывает вызов p.greeting1() как эквивалентный (&p).greeting1(). Как сказал mkopriva в комментарии, это ясно изложено в спецификации Go:

Вызов метода xm() действителен, если набор методов (тип) x содержит m и список аргументов можно назначить списку параметров m. Если x адресуемый и & x набор методов содержит m, xm() является сокращением для (& x).m()

Это сделано для удобства. Так как приемники указателей весьма необходимы и популярны в Go - они нужны вам всякий раз, когда ваш метод изменяет базовый объект - это помогает писать более чистый код. Вы не должны быть обязаны писать (&p).greeting1() где будет делать p.greeting1() - эта замена однозначна, так как компилятор знает, какие методы определены в Person и с какими получателями.

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

Когда значение адресуемое, язык заботится о распространенном случае вызова метода указателя для значения путем автоматической вставки оператора адреса. В нашем примере переменная b является адресуемой, поэтому мы можем вызвать ее метод Write с помощью только b.Write. Компилятор перепишет это в (& b). Напишите нам.

ответил(а) 2021-01-19T22:21:44+03:00 2 месяца, 3 недели назад
44

На самом деле Go - объектно-ориентированный язык по-своему. Он использует структуру вместо классов. Если вы хотите иметь класс, вы должны создать структуру и связать с ней некоторые функции с помощью указателя этой структуры, поэтому позже вы можете создать много независимых объектов из вашей структуры. Вы можете использовать функцию new, которая будет возвращать указатель вашей структуры. Подобно:

p:=new(person)
p.name = "joe"
p.age = 41
p.greeting1()

ответил(а) 2021-01-19T22:21:44+03:00 2 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема