Notes
Go
数组和指针

数组和指针

数组

数组是一种数据结构,用于存储固定长度的相同类型的元素。

数组的声明

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 中,对于对象类型的参数传入函数时都默认传入的是指针。