В большинстве объектно-ориентированных языков, таких как 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 основные причины:
- В языке Go, кроме map, slice и chan, другие типы передаются по значению в параметрах функции.
- Язык Go не является объектно-ориентированным языком, поэтому во многих случаях при реализации структурных методов необходимо использовать типы указателей для реализации ссылочных объектов структур.
- Указатель также является типом, реализующим интерфейс.
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)++
}
- f определяет параметр с
*int
заменятьint
, объявляет, что параметр является указателем типа int - При вызове функции нельзя напрямую передать переменную типа int.
i
, но чтобы пройти&
получитьi
адрес - В функции f параметр
count
Теперь это указатель, его нельзя распечатать напрямую, нужно использовать*
Получить значение, хранящееся в адресе, на который указывает этот указатель -
count
Значение +1. - Вызов функции 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 почти такое же.
в заключении:
- Указатели очень часто используются в языке Go, и их необходимо освоить.
- В дополнение к map, slice и chan язык Go передается по значению, а тип указателя должен использоваться для передачи ссылки.
- Метод определения типа структуры должен обратить внимание на использование типа указателя
- Когда интерфейс реализует метод, функция интерфейса, реализованная с помощью типа указателя, может быть реализована только как тип указателя, а метод, реализованный с помощью типа структуры, также реализован как тип указателя.
Добро пожаловать для обсуждения и изучения языка Go вместе! !
Добро пожаловать в официальный аккаунт, давайте учиться программированию со всеми