指针是一种数据类型
// 声明一个 字符串类型 的变量(默认初始化值为空字符串)
var s1 string
// 声明一个 字符串的指针类型 的变量(默认初始化值为nil)
var s2 *string
用于表示数据的内存地址
// 声明一个 字符串类型 的变量, 值为august
var name stirng = "august"
// 声明一个 字符串的指针类型 的变量,值为 name 对应的内存地址
var pointer *string = &name
当我们定义一个变量name
var name stirng = "August Rush"
此时,name是变量名,它只是编程语言中方便程序员编写和理解代码的一个标签。
当我们访问这个标签时,计算机会返回给我们它指向的内存地址里存储的值:August Rush
出于某些需要,我们会将这个内存地址
赋值给另一个变量名,而这个变量,我们称之为指针变量
。
换句话说,指针变量的值是指针,也就是内存地址。
根据变量指向的值,是否是内存地址,我们把变量分为两种:
Go语言中的指针不能进行偏移和运算,因此Go语言中的指针操作非常简单,我们只需要记住两个符号:&
(取地址)和*
(根据地址取值)。
指针的创建有三种方式
先定义对应的变量,再通过变量取得内存地址,创建指针
// 定义一个普通变量
num := 13
// 定义一个指针变量
numPtr := &num
先创建指针,分配好内存后,再给指针指向的内存地址写入对应的值。
// 创建指针
str := new(string) // 此时初始化一个指针变量,并指向nil
// 给指针赋值
*str = "world peace"
先声明一个指针变量,再从其他变量取得内存地址赋值给它
num := 13
var numPtr *int // 声明一个指针
numPtr = &num // 初始化
相当于创建了一个地址的引用
,以后根据这个引用再去获取它里面的值
。
关于指针的两个符号:
&
: 从一个普通变量中取得内存地址
*
: 当*
在赋值操作符(=)的右边,是从一个指针变量中取得变量值,当*
在赋值操作符(=)的左边,是指该指针指向的变量
v1 := "august"
v2 := &v1
fmt.Println(v1, v2, *v2)
v1 = "alex"
fmt.Println(v1, v2, *v2)
// v2 = "eric" 报错
*v2 = "eric"
fmt.Println(v1, v2, *v2)
要想打印指针指向的内存地址,方法有两种:
// 第一种
fmt.Printf("%p", ptr)
// 第二种
fmt.Println(ptr)
Go语言中的值类型
(int、float、bool、string、array、struct)都有对应的指针类型,如:*int
、*int64
、*string
等。
package main
import "fmt"
func main() {
astr := "hello"
aint := 1
abool := false
arune := 'a'
afloat := 1.2
fmt.Printf("astr 指针类型是:%T\n", &astr)
fmt.Printf("aint 指针类型是:%T\n", &aint)
fmt.Printf("abool 指针类型是:%T\n", &abool)
fmt.Printf("arune 指针类型是:%T\n", &arune)
fmt.Printf("afloat 指针类型是:%T\n", &afloat)
}
/*
输出结果:
astr 指针类型是:*string
aint 指针类型是:*int
abool 指针类型是:*bool
arune 指针类型是:*int32
afloat 指针类型是:*float64
*/
当指针声明后,没有进行初始化,其默认值是nil。
func main() {
a:=25
var b * int
if b == nil {
fmt.Println(b)
b = &a
fmt.Println(b)
}
}
/*
输出结果:
<nil>
0xc0000100a0
*/
切片与指针一样,都是引用类型。
如果我们想通过一个函数改变一个数组的值,有两种方法
尽管两者都可以实现我们的目的,但是按照Go语言的使用习惯,建议使用第一种方法,写出来的代码会更加简洁,易读。
func modify(sls []int) {
sls[0] = 96
}
func main() {
a := [3]int{89, 90, 91}
modify(a[:])
fmt.Println(a)
}
func modify(arr *[3]int) {
(*arr)[0] = 96
}
func main() {
a := [3]int {89, 90, 91}
modify(&a)
fmt.Println(a)
}
Go语言中new
和make
是内建的两个函数,主要用来分配内存
在Go语言中对于引用类型
的变量,我们在使用的时候不仅要声明它,还要为它分配内存空间,否则我们的值就没办法存储。而对于值类型
的声明不需要分配内存空间,是因为它们在声明的时候已经默认分配好了内存空间。
new是一个内置的函数
func new(Type) *Type
其中:
new函数得到的是一个类型的指针,并且该指针对应的值为该类型的默认值。
func main() {
a := new(int)
b := new(bool)
fmt.Printf("%T\n", a)
fmt.Printf("%T\n", b)
fmt.Println(*a)
fmt.Println(*b)
}
/*
输出结果:
*int
*bool
0
false
*/
var a *int
只是声明了一个指针变量a但是没有初始化,指针作为引用类型需要初始化后才会拥有内存空间,才可以给它赋值。应该按照如下方式使用内置的new函数对a进行初始化之后就可以正常对其赋值了
func main() {
var a *int
a = new(int)
*a = 10
fmt.Println(*a)
}
make也是用于内存分配的,区别于new,它只用于slice、map以及channel的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回它们的指针了。
func make(t Type, size ...IntegerType) Type
make函数是无可替代的,我们在使用slice、map以及channel的时候,都需要使用make进行初始化,然后才可以对它们进行操作。
而var b map[string]int
只是声明变量b是一个map类型的变量,需要使用make函数进行初始化操作之后,才能对其进行键值对赋值
func main() {
var b map[string]int
b = make(map[string]int, 10)
b["age"]=18
fmt.Println(b)
}
当希望值随着修改,变量引用的值也随之修改时。便可用指针来完成
name := "august"
copyName := name
fmt.Println(name, &name)
fmt.Println(copyName, ©Name)
name = "alex"
fmt.Println(name, &name)
fmt.Println(copyName, ©Name)
/*
输出结果:
august 0xc00008e1e0
august 0xc00008e1f0
alex 0xc00008e1e0
august 0xc00008e1f0
*/
name := "august"
copyName := &name
fmt.Println(name, &name)
fmt.Println(*copyName, copyName, ©Name)
name = "alex"
fmt.Println(name, &name)
fmt.Println(*copyName, copyName, ©Name)
/*
输出结果:
august 0xc000010200
august 0xc000010200 0xc00000e028
alex 0xc000010200
alex 0xc000010200 0xc00000e028
*/
当需要传参数给函数时,其本质是先把数据拷贝一份再赋值给函数体的对应参数
package main
import "fmt"
func main() {
name := "august"
modify(name)
fmt.Println(name)
}
func modify(passName string) {
passName = "alex"
}
// 输出结果: august
package main
import "fmt"
func main() {
name := "august"
modify(&name)
fmt.Println(name)
}
func modify(passName *string) {
*passName = "alex"
}
// 输出结果: alex
var username string
fmt.Scanf("%s", &username)
fmt.Println(username)
name := "武沛齐"
// 声明一个指针类型变量p1,内部存储name的内存地址
var p1 *string = &name
// 声明一个指针的指针类型变量p2,内部存储指针p1的内存地址
var p2 **string = &p1
// 声明一个指针的指针的指针类型变量p3,内部存储指针p2的内存地址
var p3 ***string = &p2
fmt.Println(name, &name)
fmt.Println(p1, &p1, *p1)
fmt.Println(p2, &p2, *p2)
fmt.Println(p3, &p3, *p3)
/*
输出结果:
武沛齐 0xc000010200
0xc000010200 0xc00000e028 武沛齐
0xc00000e028 0xc00000e030 0xc000010200
0xc00000e030 0xc00000e038 0xc00000e028
*/
基于Nginx+Supervisord+uWSGI+Django1.11.1+Python3.6.5构建