Go语言-2

一、复合数据结构

Go的复合类型包含数组、切片、map、结构体。

1. 数组 Array

数组是固定长度、元素类型相同 的连续内存集合。数组长度属于类型的一部分,[3]int 和 [5]int 是两种完全不同的类型。

数组属于值类型,赋值或者传给函数时,会完整复制一份全部元素,数据量大的时候性能开销高,所以业务代码很少直接使用数组,数组更多是切片的底层载体。

go 复制代码
package main

import "fmt"

func main() {
	// 声明,默认零值初始化
	var arr [3]int
	arr[0] = 10
	arr[1] = 20
	arr[2] = 30
	fmt.Println(arr)

	// 简写初始化
	arr2 := [3]string{"Go", "Rust", "C++"}
	fmt.Println(arr2)

	// 自动推导长度
	arr3 := [...]int{1, 2, 3, 4}
	fmt.Printf("arr3类型:%T\n", arr3)
}
  1. 长度一旦定义,不能扩容;
  2. 遍历可以用for或者for range;
  3. 值拷贝,函数接收数组参数会复制整个数组,大数组不推荐。

2. 切片 Slice

切片是Go开发中最常用 的数据结构,它并不是数组,而是对底层数组的引用视图。

切片结构包含三部分:指针(指向底层数组)、len(当前有效元素长度)、cap(底层数组容量) 。切片是引用类型。

go 复制代码
package main

import "fmt"

func main() {
	// 方式1:直接字面量创建切片
	s := []int{10, 20, 30}
	fmt.Println("len:", len(s), "cap:", cap(s))

	// 方式2:make创建,make(类型, len, cap)
	s2 := make([]int, 2, 5)
	fmt.Println(s2)

	// append追加元素,超过cap自动扩容
	s = append(s, 40, 50)
	fmt.Println(s)

	// 切片截取 s[low:high],左闭右开,新切片和原切片共享底层数组
	s3 := s[1:3]
	s3[0] = 999
	fmt.Println("原切片", s)
}
  1. 切片截取后共享底层数组,修改新切片会影响原切片;
  2. append扩容时,如果容量不足,会开辟新数组,不再共享底层;
  3. nil切片:var s []int,本身没有底层数组,可以直接append;空切片make([]int,0)有底层数组。

3. map

map是键值对(key-value)集合,适合根据key快速查找数据。map是引用类型 。

map的key必须是可比较的类型(int、string等,不能是切片、map、函数);key唯一,重复赋值会覆盖旧值;map内部元素无序,遍历顺序每次可能不一样

go 复制代码
package main

import "fmt"

func main() {
	// 声明map,nil,不能直接写入key
	var m map[string]int

	// 必须make初始化
	m = make(map[string]int)
	m["age"] = 22
	m["score"] = 95
	fmt.Println(m["age"])

	// 获取值,同时判断key是否存在
	val, ok := m["name"]
	if ok {
		fmt.Println("name:", val)
	} else {
		fmt.Println("key不存在")
	}

	// 删除key
	delete(m, "age")
}
  1. 只var m map[xxx]不make,直接写键会panic;
  2. 遍历for range map每次顺序不同;
  3. map的value如果是结构体,不能直接修改结构体内部字段,需要取出或者用指针。

4. 结构体 struct

结构体可以把不同类型的字段 组合在一起,用来描述现实中的实体,比如用户、订单。结构体是自定义类型,可以绑定方法,是Go实现面向对象思想的基础。

go 复制代码
package main

import "fmt"

// 定义结构体
type User struct {
	Name string
	Age  int
}

func main() {
	// 初始化方式1:按顺序赋值
	u1 := User{"lisi", 20}
	// 初始化方式2:指定字段名,推荐,顺序无关
	u2 := User{Name: "wangwu", Age: 21}

	fmt.Println(u1.Name, u1.Age)
	fmt.Println(u2)

	// 修改字段
	u2.Age = 22
	fmt.Println(u2)
}
  1. 字段首字母大写,包外可以访问;小写只能当前包访问;
  2. 结构体可以嵌套结构体;
  3. 结构体本身是值类型,赋值会完整拷贝;结构体指针则不会拷贝。

二、函数

参数、变量、返回值。函数支持多返回值,这是Go最标志性的特性,通常用第二个返回值返回error。

基础函数定义

语法:func 函数名(参数列表) (返回值列表) {函数体}

go 复制代码
package main

import "fmt"

// 普通函数,两个入参,一个返回值
func add(a int, b int) int {
	return a + b
}

// 多返回值,第二个返回error
func div(a, b int) (int, error) {
	if b == 0 {
		return 0, fmt.Errorf("除数不能为0")
	}
	return a / b, nil
}

func main() {
	sum := add(3, 5)
	fmt.Println(sum)

	res, err := div(10, 2)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(res)
	}
}

1. 可变参数

...类型代表可变参数,可以传入任意多个同类型参数,可变参数本质就是切片。可变参数必须放在参数列表最后。

go 复制代码
func sum(nums ...int) int {
	total := 0
	for _, v := range nums {
		total += v
	}
	return total
}

func main() {
	fmt.Println(sum(1, 2, 3))
	fmt.Println(sum(10, 20))
}

2. 匿名函数与闭包

匿名函数:没有函数名,可以直接赋值给变量或者立即执行。

闭包:匿名函数捕获函数外部的变量,闭包保存的是变量引用,不是变量快照。

go 复制代码
package main
import "fmt"

func main() {
	// 匿名函数赋值给变量
	f := func(x int) int {
		return x * 2
	}
	fmt.Println(f(6))

	// 闭包示例
	a := 10
	closure := func() {
		a++
		fmt.Println(a)
	}
	closure()
	closure()
}

3. 方法(绑定到结构体的函数)

方法和普通函数的区别:方法带有接收者,接收者写在函数名前面。分值接收者 和指针接收者。

  • 值接收者:传入结构体副本,方法内部修改不会影响原结构体,开销大,适合小结构体、只读场景。
  • 指针接收者:传入结构体指针,直接操作原结构体,不会拷贝,开发优先使用指针接收者。
go 复制代码
package main
import "fmt"

type User struct {
	Name string
}

// 值接收者
func (u User) Hello() {
	fmt.Println("hello,", u.Name)
}

// 指针接收者,可以修改原结构体
func (u *User) Rename(newName string) {
	u.Name = newName
}

func main() {
	u := User{Name: "zhangsan"}
	u.Hello()
	u.Rename("newName")
	fmt.Println(u.Name)
}

4. 函数参数传递规则

  • 值类型:基础类型int、bool、string、数组、结构体。传参是拷贝副本,函数内部修改不影响外部原始变量。
  • 引用类型:切片、map、channel。传参拷贝的是引用头,底层数据共享,函数内修改底层数据会影响外部。
相关推荐
星夜离尘561 小时前
MATLAB 工程实验:不等间隔流量积分,先把缺口与覆盖率说清楚
开发语言·matlab·时间戳·数据质量·数值积分
Ai-_Man2 小时前
Meta Muse还是不可以导出左侧所有对话,只能点进去单条内容导出,方法不对吗?
开发语言·人工智能·ai·小程序·c#·1024程序员节
梓豪csd2 小时前
消息订阅中心:谁该收到哪条通知
java·开发语言·人工智能·低代码·自动化·1024程序员节
学逆向的2 小时前
C 枚举变量
c语言·开发语言·网络安全
Sakura_j_h_2 小时前
Python 在定时任务里输出 emoji,UnicodeEncodeError 从哪来
开发语言·字符编码·windows·python·定时任务
企业数字化笔记4 小时前
视频人体姿态怎么做三维可视化?2D关键点、深度局限与技术选型
人工智能·算法·音视频
?abc!5 小时前
(数组)581. 最短无序连续子数组
数据结构·算法·leetcode
小成202303202658 小时前
C++~07补充
开发语言·c++
小郎君6588 小时前
MPTT树复选框的半选状态:一棵百万节点树从递归到计数器,再到区间覆盖
算法
酌沧8 小时前
MemT让记忆成为模型内生能力
jvm·人工智能·算法