数组和指针
数组
数组是一种数据结构,用于存储固定长度的相同类型的元素。
数组的声明
Go 语言中数组的声明格式为:
var 数组名 [数组长度]数组类型
示例如下:
package main
import "fmt"
func main() {
a := [3]int{1, 2, 3}
// 或
var b [3]int
b = [3]int{4, 5, 6}
// 或
var c [3]int = [3]int{7, 8, 9}
}
访问数组
数组的访问方式为 数组名[索引]
。
package main
import "fmt"
func main() {
a := [3]int{1, 2, 3}
fmt.Println(a[0]) // 1
fmt.Println(a[1]) // 2
fmt.Println(a[2]) // 3
}
数组传入函数
数组作为参数传入函数时,会传入数组的副本,而不是数组的指针。
package main
import "fmt"
func modify(a [3]int) {
a[0] = 4
fmt.Println(a) // [4 2 3]
}
func main() {
a := [3]int{1, 2, 3}
modify(a)
fmt.Println(a) // [1 2 3]
}
这表明,数组作为参数传入函数时,数组将被全量复制,而不是传入原数组的指针。
数组无法改变大小
Go 语言中的数组是固定长度的,无法改变大小。这是因为数组在内存中是连续存储的,如果改变大小,将会导致内存的重新分配,这将导致性能问题。
修改数组的值
数组的值可以通过索引来修改。
package main
import "fmt"
func main() {
a := [3]int{1, 2, 3}
a[0] = 4
fmt.Println(a) // [4 2 3]
}
指针
指针的基本概念
在许多语言如 Python、Java 中,指针概念被屏蔽,但是在 Go 语言中,指针被保留了下来。
指针是存储另一个变量的内存地址的变量。
var a int = 1
var b *int = &a
这里的 *int
表示指向 int
类型的指针,&a
表示变量 a
的内存地址。
&
表示取地址符,*
表示取指针的值。
一个例子:
package main
import "fmt"
func main() {
var a = 65336
fmt.Println("值类型 a 的值为:", a)
var b = 65336
var c = &b
fmt.Println("指针类型 c 的值为:", c)
}
输出结果:
值类型 a 的值为: 65336
指针类型 c 的值为: 0xc0000b6010
在上述案例中,c 得到的值是通过 &
符号(取地址符)得到的,这个值是一个内存地址,因此打印的结果是一个内存地址。
为什么区分指针和值类型
如我们在数组中提到的,数组作为参数传入函数时,会传入数组的副本,而不是数组的指针。同样地,传入的参数都会被复制:
func tryChange(account Account) {
account.Modify()
}
但是上面的代码中,account
是一个结构体,结构体是值类型,所以 account
会被复制一份,而不是传入的指针。如果我们想要修改原始的 account
,这将无法实现。
所以,我们可以使用指针来传递参数:
func tryChange(account *Account) {
account.Modify()
}
这样,account
就是一个指针,指向原始的 account
,这样就可以修改原始的 account
。
在 Java 中,对于对象类型的参数传入函数时都默认传入的是指针。