golang 中的复合类型

前言 所有的api文档都可以使用bash命令 go doc 查看文档的帮助信息
从 Go 1.13 开始,godoc 不再随 Go 发行版一起安装,你需要单独安装它。
需要单独安装
1. go install golang.org/x/tools/cmd/godoc@latest
2执行命令 godoc -http=:1111 打开浏览器 http://localhost:1111/pkg/ 即可查看文档

复合类型

作为java人,go中的数据类型分为基本数据类型 和复合数据类型 基本数据类型都很好记 int8 int16 int32 int64 uint8 uint16 uint32 uint64 rune 也是int32 如果有
在这里插入图片描述
值得注意的是go 字符就是采用int32 存储

	// 字符类型 同时这个也是int32
	var char rune = 'A'
	fmt.Println("Character:", char)//输出asc码 65

	// 字节类型 同时无符号unit8
	var byteVal byte = 'B'
	fmt.Println("Byte:", byteVal)
	// 字符类型 同时这个也是int32 采用%c 格式化
	var char rune = 'A'
	fmt.Printf("Character:%c\n", char)

	// 字节类型 同时无符号unit8
	var byteVal byte = 'B'
	fmt.Printf("Byte:%c\n", byteVal)	

其中有个好玩的的类型iota

一个自增数 可以配合使用作为枚举或者状态码使用

	/**
	iota是go语言中的一个特殊类型 可以编译器认为是自动修改的常量
	*/
	const (
		a = iota
		b = iota
		c = iota
		d = iota
		e = iota
		f = iota
	)
	fmt.Println(a, b, c, d, e, f)
	println("一组常量值的iota初始值为0")
	const (
		//由于常量中如果不申明变量的话和上一个一样 那么可以利用这个特性来写iota
		male = iota
		female
		other
	)

	println(male, female, other)

编辑器就把这个结果输出了
在这里插入图片描述

数组 arrary

数组虽然是复合类型 可以存储多个同类型数据,但是在go中是值传递 不是引用传递

申明方式
	var arr [5]int //声明一个长度为5的整型数组
	arr[0] = 10
	arr[1] = 20
	arr[2] = 30
	//申明赋值同时进行
		var arr2 [5]int = [5]int{10, 20, 30, 30, 30}
		var arr3 = [5]int{10, 20, 30, 30, 30}
		arr4=:[3]{1,2,3}
	var arr5 = [...]int{10, 20, 30, 30, 30} //简短声明方式 ...自动根据已有的元素长度申明
	//索引10为20 索引30=30
	var arr6 = [...]int{10: 20, 30: 30}     //简短声明方式  这赋值就是数组特定位置有值 其他位置为数组类型默认	

遍历 foreach和fori
	defer fmt.Println("遍历方法完成")
	arr := [5]int{10, 20, 30, 30, 30}
	//for i := 0; i < len(arr); i++ {
	//	//经典的for i
	//	fmt.Println(arr[i])
	//}
	for index, value := range arr {
		//range 遍历数组   遍历返回索引和值 map返回 key 和 value
		fmt.Println(index)
		fmt.Println(value)
	}
	for value := range arr {
		//致谢一个返回值是索引

		fmt.Println(value)
	}

并且数组在go中也算值传递 传递的是数值

	arr1 := [...]int{10, 20, 30, 30, 30}
	arr2 := arr1
	arr2[0] = 100
	//若改变arr2的值  arr1的值也会改变 那就arr2是arr1的一个引用
	fmt.Println("arr1", arr1) //而java中数组是引用传递
	fmt.Println("arr2", arr2)
	fmt.Printf("arr1%p\n", &arr1) //而java中数组是引用传递
	fmt.Printf("arr2%p\n", &arr2)
	//输出结果只有2改变
	fmt.Println(arr1 == arr2) //false 如果改成一样的
	arr2[0] = 10
	fmt.Println(arr1 == arr2) //true 此时大小相同 容量相同是同一个数组

输出 改变赋值对象 原数组不会改变 并且输出地址也不想等
在这里插入图片描述

切片 (slice) 动态数组

和java中的list一样,为了解决数组大小固定 限制而决定的的数据结构 引用类型,引用类型如果只申明变量 (只有地址没有空间) 那么默认值都是nil(java中的null) 小提示:java中字符串是字符数组 而go中每个字符串是字符切片

申明方式
//申明数组时不写具体范围
	var splice []int //申明方式1
	for i := 0; i < 20; i++ {
		//早就草果范围但是底层扩容
		splice = append(splice, 4) //添加元素

	}

append 源码 传递指定的元素 或者其他切片… 返回该整合的新切片
在这里插入图片描述

融合其他切片

	splice1 = append(splice1, slice2...) //添加元素
//make 方式推荐
	//make 创建引用数据类型的切片 ,map,chanel
	/**
	  make(type, len, cap)
	  type:类型
	  len:长度
	  cap:容量
	  细节 如果操作没有数据的索引会报错 比如 make([]string, 3, 10) 长度为3 容量为10 但是索引为4 就会报错 因为只有3个数据
	*/
	var list = make([]string, 0, 10) //对应ArrayList<string>
		// 创建一个字符串到整数的映射
	//dictionary := make(map[string]int)  对应new hashnap
	// 创建一个有缓冲区大小为5的整数通道
	//ch := make(chan int, 5)
从已有数组创建切片
	arrayy := [5]int{1, 2, 3, 4, 5}

	fmt.Println("从已有数组创建切片")
	slicedemo := arrayy[1:3] //从索引1到索引3的切片[:) 实际 0-2

	fmt.Println(slicedemo)
	//slice = append(slice, 6) //添加第6元素
	//slice = append(slice, 6) //添加第6元素
	//slice = append(slice, 6) //添加第6元素
	//slice = append(slice, 6) //添加第6元素
	fmt.Println("实际长度", len(slicedemo)) //
	fmt.Println("容量是", cap(slicedemo))  //从开始索引到末尾
	fmt.Printf("%p\n", &slicedemo)//俩个地址不一致 说明创建的切牌开启了新空间
	fmt.Printf("%p\n", &arrayy)
遍历 和数组一样 for 和foreach都可以
	//遍历切片 __表示临时变量只接受返回数据无法引用
	for _, v := range list {
		println(v)
	
	}
细节
	fmt.Println("detail 切片 map 通道都是引用类型变量赋值后修改变量原属性也会影响到其他变量")
	slice := []int{1, 2, 3, 4, 5}
	fmt.Println(slice)
	slice2 := slice
	slice2[0] = 100 //修改的是切片2
	fmt.Println("修改切片2后原来的切片也会被修改")
	fmt.Println(slice[0])
	fmt.Println(slice)
	/**
	动态扩容的算法和java 一样一旦超过容量就扩容2倍
	*/
	fmt.Println("动态扩容的算法和java 一样一旦超过容量就扩容2倍,当前容量为5刚好填满", cap(slice))
	slice = append(slice, 6) //添加第6元素
	fmt.Println("添加第6元素后容量变为10,容量为2倍:", cap(slice))

说明是引用传递,修改传递的数据后,原来的数据也会被修改,并且扩容和java也是容量二倍扩容
在这里插入图片描述
但是类型还是数组go中表示切片也是底层是该类型切片的数组

var sli []int = make([]int, 0, 4)
	fmt.Printf("实际类型%T\n", sli)   

在这里插入图片描述

深拷贝实现

既然赋值方式是浅拷贝智能传递地址 那么手动实现深度拷贝

	slice := make([]int, 0, 10)
	for i := 0; i < cap(slice); i++ {
		slice = append(slice, rand.Intn(10))
	} //随机赋值10以内的元素
	var slice2 []int
	for i := 0; i < len(slice); i++ {
		slice2 = append(slice2, slice[i])
		//slice2 = append(slice2, slice...)
	}
	fmt.Println("原始切片:", slice)
	fmt.Printf("克隆后的切片%p\n", &slice)
	fmt.Printf("克隆后的切片:%p\n", &slice2)

api方式 copy

	 var slice3 []int 
	copy(slice3, slice)
	//截取某段数据[)
	copy(slice3, slice[2:])
//	返回复制的元素数

map 映射

和java一样也是一种key value的数据结构,无序 key 唯一

申明方式

引用类型创建前 没有申明空间会报错

	var address map[string]string = map[string]string{
		"localhost": "localhost",
		"name": "上海",
	}

细节

	var address map[string]string
	//会报错 nil
	address["John"] = "123 Main St"

在这里插入图片描述

	//只有申明了空间才可以操作
	var address map[string]string = map[string]string{}

	address["John"] = "123 Main St"

make(之前提到的 引用数据类型)

  	telebook := make(map[string]string)
//
	telebook["John"] = "123 Main St"
	telebook["Jane"] = "456 Oak Ave"

删除和获取当前长度


	fmt.Print("当前映射的长度", len(telebook))
	delete(telebook, "John")//key如果不存在也不会报错
	fmt.Print("当前映射的长度", len(telebook))

遍历

	telebook := map[string]string{
		"坤哥": "有事打我电话",
		"刀哥": "eqe芭蕾 eq一亏嘞",
		"顶真": "我测尼玛",
	}
	for k, v := range telebook {
		fmt.Println(k, v)
	}
	//和遍历数组一样 数值在第二个
	for k := range telebook {
		//返回的是key
		fmt.Println(k)
	}
map结合slice

打造 list 的效果

	//切片 一个map list
   userinfos := make([]map[string]string, 0, 10)
   info := map[string]string{
   	"name": "kong",
   	"age":  "25",
   	"sex":  "male",
   }
   userinfos = append(userinfos, info)
   userinfos = append(userinfos, userinfo)

注意因为(list) slice 是可以重复的有序的 所以可以添加多个同一个map
这样的化修改其中一个map 那么另外的也会被修改 因为是引用传递

userinfos = append(userinfos, userinfo)
userinfos = append(userinfos, userinfo)

在这里插入图片描述
所以如果要添加同样数据的map :=map {} 对应数据

channel

通道用于俩个携程之前进行通信

申明

	ch := make(chan int) 

使用

	// WaitGroup 用于等待一组 Goroutines 完成
	var wg sync.WaitGroup
	for i := 0; i < 3; i++ {
		wg.Add(1) // 增加 WaitGroup 的计数
		go func(id int) {
			defer wg.Done()                             // 在函数返回时调用 Done 来通知 WaitGroup 该 Goroutine 完成了
			time.Sleep(time.Duration(id) * time.Second) // 延迟一定时间以模拟工作
			ch <- id                                    // 将当前的 id 发送到 Channel
		}(i) // 传入当前的 id 作为参数
	}
	// 启动一个 Goroutine 来接收数据
	go func() {
		wg.Wait() // 等待所有发送 Goroutine 完成
		close(ch) // 关闭 Channel
	}()

	// 从 Channel 中读取数据
	for value := range ch {
		fmt.Println("Received:", value)
	}

引用类型
影响范围:如果你复制了一个 channel 变量到另一个变量,两个变量实际上指向同一个 channel。因此,向一个变量代表的 channel 中发送数据或者从中接收数据,都会影响到另一个变量。这表明 channel 在赋值时表现得像引用类型。

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Golang ,泛型被称为参数化类型,可以使用类型参数来定义。在函数或结构体使用类型参数,可以使代码更加灵活,同时也可以提高代码的可复用性。 定义一个泛型函数的语法如下: ```go func 函数名[T any](参数列表) 返回值列表 { // 函数体 } ``` 在函数名后面的方括号定义类型参数 T,使用 `any` 关键字表示 T 可以是任何类型。在函数体,可以使用 T 来表示任意类型。 下面是一个利用泛型实现排序的例子: ```go package main import ( "fmt" "sort" ) func main() { nums := []int{3, 2, 1, 4, 5} strs := []string{"hello", "world", "go", "lang"} sort.Slice(nums, func(i, j int) bool { return nums[i] < nums[j] }) fmt.Println(nums) sort.Slice(strs, func(i, j int) bool { return strs[i] < strs[j] }) fmt.Println(strs) } ``` 在上述代码,我们使用了 `sort.Slice` 函数来对切片进行排序。该函数接受两个参数,第一个参数是要排序的切片,第二个参数是一个函数,用于比较两个元素的大小。由于比较函数的参数类型是不确定的,我们可以使用泛型类型参数来代表这个类型。在上述代码,我们使用了 `int` 和 `string` 两种类型进行排序,但是可以使用任何类型来进行排序。 泛型是 Golang 的一个重要特性,可以提高代码的灵活性和可复用性。但是,目前 Golang 还没有完全支持泛型,只能使用泛型类型参数来实现一些简单的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝胖子不是胖子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值