go的数组、结构体

87 次阅读

一、数组(Array)

1. 数组核心特性

  1. 长度固定,声明时必须指定长度,长度属于数组类型的一部分
  2. 值类型,赋值、传参时会完整拷贝一份数据
  3. 下标从 0 开始访问元素,下标越界直接编译/运行报错
  4. 支持 len() 获取数组长度

2. 数组声明与初始化

package main

import "fmt"

func main() {
	// 1. 仅声明,使用类型默认零值填充
	var arr1 [3]int
	fmt.Println(arr1) // [0 0 0]

	// 2. 声明同时赋值
	var arr2 [3]int = [3]int{10, 20, 30}
	fmt.Println(arr2)

	// 3. 类型推导简写
	arr3 := [3]string{"Go", "Java", "Python"}

	// 4. 自动推导长度 ...
	arr4 := [...]int{1, 2, 3, 4, 5}
	fmt.Println(len(arr4)) // 5

	// 5. 指定下标初始化,未赋值元素填零值
	arr5 := [5]int{1: 99, 3: 66}
	fmt.Println(arr5) // [0 99 0 66 0]
}

3. 数组元素读写

func main() {
	arr := [3]int{1, 2, 3}
	// 读取
	fmt.Println(arr[0])
	// 修改
	arr[1] = 99
	fmt.Println(arr) // [1 99 3]
}

4. 数组遍历

方式1:普通for循环

arr := [3]int{10, 20, 30}
for i := 0; i < len(arr); i++ {
	fmt.Printf("下标:%d,值:%d\n", i, arr[i])
}

方式2:range 遍历

arr := [3]int{10, 20, 30}
for idx, val := range arr {
	fmt.Println(idx, val)
}
// 只取值,丢弃下标
for _, val := range arr {
	fmt.Println(val)
}

5. 数组是值类型(拷贝特性)

数组赋值会完整复制,修改副本不会影响原数组

func main() {
	a := [2]int{1, 2}
	b := a
	b[0] = 99
	fmt.Println(a) // [1 2] 原数组不变
	fmt.Println(b) // [99 2]
}

如需修改原数组,使用数组指针传参/赋值。

6. 多维数组

func main() {
	// 二维数组:2行3列
	var twoArr [2][3]int
	twoArr[0][0] = 10

	// 初始化
	arr := [2][3]int{
		{1, 2, 3},
		{4, 5, 6},
	}
	fmt.Println(arr[1][2]) // 6
}

二、结构体(struct)

1. 结构体作用

自定义复合数据类型,把多个不同类型变量封装在一起,Go 实现面向对象的基础。

2. 结构体定义语法

type 结构体名 struct {
	字段名1 类型1
	字段名2 类型2
	...
}

示例:

type Student struct {
	name string
	age  int
	score float64
}

3. 结构体实例化 4 种方式

package main

import "fmt"

type Student struct {
	name  string
	age   int
	score float64
}

func main() {
	// 方式1:按字段顺序赋值
	s1 := Student{"小明", 18, 92.5}

	// 方式2:指定字段名赋值(推荐,顺序无关)
	s2 := Student{
		name:  "小红",
		score: 96,
		age:   17,
	}

	// 方式3:仅声明,字段填充零值
	var s3 Student
	fmt.Println(s3) // { 0 0}

	// 方式4:结构体指针
	s4 := &Student{"小李", 19, 88}
	fmt.Println(s4.name) // 指针可直接点访问字段,自动解引用
}

4. 结构体字段读写

func main() {
	var s Student
	// 赋值
	s.name = "小张"
	s.age = 20
	// 读取
	fmt.Println(s.name, s.age)
}

5. 结构体是值类型

赋值、传参时整体拷贝,副本修改不影响原数据

func main() {
	s1 := Student{"张三", 18, 90}
	s2 := s1
	s2.name = "李四"
	fmt.Println(s1.name) // 张三,原数据不变
}

6. 结构体指针(修改原数据)

func modifyStu(s *Student) {
	s.age = 99
}

func main() {
	s := Student{"测试", 16, 80}
	modifyStu(&s)
	fmt.Println(s.age) // 99,原结构体被修改
}

7. 结构体嵌套

7.1 普通嵌套

type Address struct {
	city string
	addr string
}

type User struct {
	name string
	addr Address
}

func main() {
	u := User{
		name: "老王",
		addr: Address{
			city: "太原",
			addr: "XX街道",
		},
	}
	fmt.Println(u.addr.city)
}

7.2 匿名嵌套(提升字段,直接访问)

type Address struct {
	city string
}

type User struct {
	name string
	Address // 匿名结构体,无字段名
}

func main() {
	u := User{
		name: "老李",
		Address: Address{
			city: "大同",
		},
	}
	fmt.Println(u.city) // 可直接访问Address的city字段
}

8. 结构体方法(绑定函数)

给结构体添加方法,区分值接收者指针接收者

type Student struct {
	name string
	age  int
}

// 值接收者:拷贝副本,无法修改原结构体
func (s Student) Show() {
	fmt.Printf("姓名:%s,年龄:%d\n", s.name, s.age)
}

// 指针接收者:操作原结构体
func (s *Student) SetAge(newAge int) {
	s.age = newAge
}

func main() {
	s := Student{"小明", 16}
	s.Show()
	s.SetAge(17)
	s.Show()
}

9. 结构体可见性规则

结构体、结构体字段首字母大写:其他包可访问;小写仅当前包可见。

// 其他包可访问
type User struct {
	Name string // 大写导出
	age  int    // 小写私有,外部包无法读取
}

三、数组 vs 结构体 核心区别

特性 数组 Array 结构体 struct
存储数据 同类型一组元素 多个不同类型字段
长度 固定不可变 无长度概念,字段固定
访问方式 数字下标 arr[0] 字段名 stu.name
适用场景 批量同类型数据 封装实体对象(用户、订单等)
类型特征 长度是类型一部分 [3]int[5]int 是两种类型 自定义独立类型