
一个变量交换的例子
交换两个变量的值在排序过程中是一个高频操作,交换变量值最直接的方式就是通过一个临时变量来实现交换,在 Go 中可以这么来实现:
func main() {
a := 10
b := 20
switchVal(a, b)
fmt.Println(a, b)
}
// 定义一个函数:交换两个变量的值
func switchVal(a int, b int) {
temp := a
a = b
b = temp
}执行上述代码,输出结果如下:
10 20根据结果来看并没有成功的实现交换两个变量的值,为什么?因为整型是值类型,作为函数参数时会将拷贝非副本作为实际的参数。

那么如何修改呢?
func main() {
a := 10
b := 20
switchVal(&a, &b)
fmt.Println(a, b)
}
// 交换两个变量的值
func switchVal(a *int, b *int) {
temp := *a
*a = *b
*b = temp
}执行上述代码,输出结果如下:
20 10根据输出结果可以确定,a 和 b 两个变量的变量值交换成功。
指针
上述代码中的 & 在之前的文章有提到过,表示获取变量的内存地址,那么 switchVal 函数中的 *int 又表示什么?
*int 表示指针类型,指针是一种数据类型,指针中存储的是内存地址,而这个内存地址指向一块具体的内存,这块具体的内存中保存着个中类型的数据。
指针类型包含两个部分,第一个是 * 符号,表示是指针类型,第二个组成部分是基本数据类型标识符,表示指针所执行的内存地址中存储的数据类型。
指针变量与普通变量不同的是,普通变量存储的直接就是变量值,而指针存储的是变量的内存地址。

func main() {
var yankee int = 200
// 定义指针
var zulu *int = &yankee
fmt.Printf("%T, %v, %v\n", yankee, yankee, &yankee)
fmt.Printf("%T, %v, %v\n", zulu, zulu, *zulu)
}执行上述代码,输出结果如下:
int, 200, 0xc0000b2008
*int, 0xc0000b2008, 200在普通变量前添加 & 就可以获得该变量的内存地址,在指针变量前添加 * 就可以获取该指针变量中的内存地址所指向的值。如果要修改指针变量内存地址指向的值只需要 *指针变量=newVal 即可。
当然定义指针变量时也可以省略 var 关键字,直接使用 := 来定义。
func main() {
xray := 1.0
whiskey := "Go"
victor := []string{"Stark", "Thor", "Steve"}
uniform := [...]int{1, 3, 5, 7, 9}
tango := map[string]string{
"code": "Tango 6",
"number": "6",
}
tangoCode := tango["code"]
fmt.Printf("%T, %v\n", &xray, &xray)
fmt.Printf("%T, %v\n", &whiskey, &whiskey)
fmt.Printf("%T, %v\n", &victor[0], &victor[0])
fmt.Printf("%T, %v\n", &uniform[0], &uniform[0])
fmt.Printf("%T, %v\n", &tangoCode, &tangoCode)
}执行上述代码,输出结果如下:
*float64, 0xc000132008
*string, 0xc000116210
*string, 0xc000118180
*int, 0xc00012a060
*string, 0xc000116220C 和 C++ 都提供了指针而且功能强大,可以进行指针的转换、偏移以及运算等,其他静态类型语言如 Java 和动态类型语言如 Python 则是将指针屏蔽,不提供指针的概念以及运算等。
Go 中的指针相比 C 和 C++ 中的指针做了很多的限制,有更高的安全性,不涉及到指针的运算、转换和偏移等功能。
先来定义一个指针变量,给指针变量的内存地址赋值,并输出其中保存在内存地址中的值
func main() {
var p *int
*p = 10
fmt.Println(*p)
}执行上述代码,输出结果如下:

这里为什么会报错呢?这里错误信息提示无效的内存地址或者空的指针指向,也就是说没有指定的内存地址来保存 10。
要初始化一个指针变量可以使用 new 函数
func main() {
var p *int = new(int)
fmt.Println(*p)
*p = 10
fmt.Println(*p)
}执行上述代码,输出结果如下:
0
10new 函数在这里会现申请一个内存空间,然后将内存空间保存的值设置为 int 的默认值既 0,而且 new 函数返回的是一个内存地址。
func main() {
var p2 *int
fmt.Println(p2) // 输出结果为:<nil>
}其他类型如 Map、Slice 如果只定义不初始化,也会报错。
func main() {
var info map[string]string
info["name"] = "Stark"
fmt.Println(info)
var namesSlic []string
namesSlic[0] = "Thor"
fmt.Println(namesSlic)
}也可以使用 make 函数来进行初始化,创建内存保存数据,返回一个具体的实例。
func main() {
var info map[string]string = make(map[string]string)
fmt.Println(info)
info["name"] = "Stark"
fmt.Println(info)
var namesSlic []string = make([]string, 3)
fmt.Println(namesSlic)
namesSlic[0] = "Thor"
fmt.Println(namesSlic)
}在 Go 编程 | 连载 11 - 复杂数据类型 Slice 中使用 new 函数创建一个 Slice 实例,因为 new 函数返回的是内存地址,要获取内存地址中保存的实例则需要使用 * 来获取。
make 函数和 new 函数的区别或者使用场景如下: