Исследование Golang: правильное использование типов указателей Golang

Go

Golang指针

В большинстве объектно-ориентированных языков, таких как C++, C# и Java, при передаче параметров функциям, помимо основных типов значений, объекты передаются по ссылке.

Однако в Go все типы (включая struct) передаются по значению, кроме map, slice и chan.

Итак, каквне функциииспользоватьПосле обработки в функцииПеременная? Только возвращая новую переменную?

Нет, указатели можно использовать

Большинство объектно-ориентированных языков редко используют сценарии указателей, но в языке Go существует множество сценариев применения указателей, которые необходимо понимать, чтобы стать квалифицированным Gopher.

концепция

Каждой переменной выделяется кусок памяти, данные хранятся в памяти, а память имеет адрес, вроде номера дома, по которому можно найти хранящиеся в ней данные.

Указатель — это переменная, которая содержит этот адрес памяти.

В языке Go используйте&получить адрес переменной

//为了说明类型,我采用了显性的变量定义方法,实际开发中更多的是用“:=”自动获取类型变量类型
var mystr string = "Hello!"
var mystrP *string = &mystr

fmt.Println(mystrP)

Введите приведенный выше код в основную функцию,go run, напечатанное содержимоеmystrадрес памяти.mystrPэтоmystrуказательная переменная.

использовать*Получить значение адреса памяти, на которое указывает переменная-указатель

Добавьте строку кода после предыдущего кода:

fmt.Println(*mystrPointer)

go runПосле запуска вы можете увидеть распечаткуmystrЗначение «Привет!»

символ*Также используется как ключевое слово для определения типов указателей.

Например:

var p *int

Сценарии применения указателя

В других ООП-языках в большинстве случаев не нужно тратить слишком много времени на манипулирование указателями, таких как Java и C#, а работа со ссылками на объекты передана виртуальной машине и фреймворку. В Go часто используются указатели. Есть 3 основные причины:

  1. В языке Go, кроме map, slice и chan, другие типы передаются по значению в параметрах функции.
  2. Язык Go не является объектно-ориентированным языком, поэтому во многих случаях при реализации структурных методов необходимо использовать типы указателей для реализации ссылочных объектов структур.
  3. Указатель также является типом, реализующим интерфейс.interfaceКогда тип структуры и тип ее указателя реализуют интерфейс по-разному

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

Передать параметр указателя в функцию

Язык Go использует передачу по значению, например:

package main

import "fmt"

func main() {
	i := 0
	f(i)
	fmt.Println(i)
}

func f(count int) {
	fmt.Println(count)
	count++
}

результат:

0
0

iБез изменений до и после выполнения

Если вы хотите, чтобы функция вызывала вас,iизменение стоимости,fПараметры функции следует изменить на*intтип. как:

func main() {
	i := 0
	f(&i)
	fmt.Println(i)
}

func f(count *int) {
	fmt.Println(*count)
	(*count)++
}
  1. f определяет параметр с*intзаменятьint, объявляет, что параметр является указателем типа int
  2. При вызове функции нельзя напрямую передать переменную типа int.i, но чтобы пройти&получитьiадрес
  3. В функции f параметрcountТеперь это указатель, его нельзя распечатать напрямую, нужно использовать*Получить значение, хранящееся в адресе, на который указывает этот указатель
  4. countЗначение +1.
  5. Вызов функции f в основной функцииmainпечатать вi.

можно увидеть результат

0
1

iзначение изменилось.

Метод типа указателя структурной структуры

Определение методов для структур в языке Go

//定义一个结构体类型
type myStruct struct {
	Name string
}

//定义这个结构体的改名方法
func (m myStruct) ChangeName(newName string) {
	m.Name = newName
}

func main() {
	//创建这个结构体变量
	mystruct := myStruct{
		Name: "zeta",
	}

	//调用改名函数
	mystruct.ChangeName("Chow")

	//没改成功
	fmt.Println(mystruct.Name)
}

Такой метод не изменит значение поля в структурной переменной. Даже если это метод структуры, если вы не используете указатель, значение структуры все равно передается в метод.

Теперь давайте вместо этого используем тип указателя для определения метода структуры.

только изменитьChangeNameфункция, с*myStructЗамена типаmyStruct

func (m *myStruct) ChangeName(newName string) {
	m.Name = newName
}

Запустите его снова, и вы увидите, что напечатанное имя изменилось.

Когда метод определен с типом указателя, переменная типа структуры автоматически получит тип указателя структуры и передаст его в метод при вызове метода.

Реализация интерфейса указателя

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

взгляните на код

//定义一个接口
type myInterface interface {
	ChangeName(string)
	SayMyName()
}

//定义一个结构体类型
type myStruct struct {
	Name string
}

//定义这个结构体的改名方法
func (m *myStruct) ChangeName(newName string) {
	m.Name = newName
}

func (m myStruct) SayMyName() {
	fmt.Println(m.Name)
}

//一个使用接口作为参数的函数
func SetName(s myInterface, name string) {
	s.ChangeName(name)
}

func main() {
	//创建这个结构体变量
	mystruct := myStruct{
		Name: "zeta",
	}

	SetName(mystruct, "Chow")

	mystruct.SayMyName()
}

Этот код не может быть скомпилирован, он предложит

cannot use mystruct (type myStruct) as type myInterface in argument to SetName:
        myStruct does not implement myInterface (ChangeName method has pointer receiver)

myStructТип не реализует метод интерфейсаChangeName, то естьfunc (m *myStruct) ChangeName(newName string)не считается реализацией интерфейса, потому что он*myStructтип реализован вместоmyStruct.

Измени это

При вызове SetName замените mystruct на &mystruct:

SetName(&mystruct, "Chow")

Скомпилируйте и запустите, успешно.

Почему интерфейс, реализованный структурным типом, также считается реализованным указателем структуры, но интерфейс, реализованный указателем, не считается интерфейсом, реализованным структурой?

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

так,&mystructнепосредственно реализует определение интерфейсаChangeNameиSayMyNameдва метода, при этомmystructможет быть достигнуто толькоSayMyName,mystructперечислитьChangeNameФактически метод вызывается после преобразования в тип указателя и не считается реализацией интерфейса.


На данный момент применение типа указателя языка Go почти такое же.

в заключении:

  1. Указатели очень часто используются в языке Go, и их необходимо освоить.
  2. В дополнение к map, slice и chan язык Go передается по значению, а тип указателя должен использоваться для передачи ссылки.
  3. Метод определения типа структуры должен обратить внимание на использование типа указателя
  4. Когда интерфейс реализует метод, функция интерфейса, реализованная с помощью типа указателя, может быть реализована только как тип указателя, а метод, реализованный с помощью типа структуры, также реализован как тип указателя.

Добро пожаловать для обсуждения и изучения языка Go вместе! !

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

晓代码公众号