- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
很好,经过很长的时间,你终于来到go语言的复合类型中,这里会介绍go语言的3种复合结构:切片(slice,可变数组),映射(map)和字符串(string).
有些老手可能会问:
1.那结构体(struct)呢,你怎么不介绍?
答:现在还没法完整地介绍结构体(struct),主要是没法介绍结构体相关的方法.
2.对于字符串(string),字符串(string)怎么会是复合类型呢?
答:字符串(string)可以认为元素无法变更的byte数组,为此我认为它是复合类型.
这里开始会有新版本的内容加入进来,本来的内容会以go1.20为主,但是由于go语言的半年更新周期,现在就必须加上go1.21的相关内容,请学习愉快! 。
题目非常地简单,让我先水一下,本题唯一的要点是使用 map[int]struct{} 这种go语言风格的 set 类型 。
26. 删除有序数组中的重复项 。
给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数.
真的有如开始所说的那样简单,使用map,注意在go语言中map是使用列表实现的,我们就可以轻松地去重 。
func removeDuplicates(nums []int) (k int) {
numMap := make(map[int]struct{}) //struct{}的大小为0,map[int]struct{}一般用作集合
k = 0
for _, v := range nums {
if _, ok := numMap[v]; !ok {
numMap[v] = struct{}{}
nums[k] = v
k++
}
}
return
}
这里说的新版本是指go1.20之后的变化, 这里解说的是近几个版本中关于复合类型的重要变化.
reflect.StringHeader在业内经常被滥用,使用不方便,很容易出现隐性问题,为了解决这个问题,go1.20对于string和[]byte类型进行高效转化,unsafe提供了 。
func String(ptr *byte, len IntegerType) string
func StringData(str string) *byte
func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType
利用上述三个函数,可以方便地进行string和[]byte的高效转化,如果你对于go1.20之前的高效转化有兴趣,可以看字符串的4.3.2章节 。
func StringToBytes(s string) []byte {
return unsafe.Slice(unsafe.StringData(s), len(s))
}
func BytesToString(b []byte) string {
return unsafe.String(&b[0], len(b))
}
在go1.21之前,你如果需要清空一个map,那么你必须进行循环delete 。
myMap := map[string]int{
"A": 1,
"B": 2,
"C": 3,
}
fmt.Println(myMap)
for k := range myMap {
delete(myMap, k)
}
fmt.Println(myMap)
而现在go1.21中你可以 。
myMap = map[string]int{
"A": 1,
"B": 2,
"C": 3,
}
fmt.Println(myMap)
clear(myMap)
fmt.Println(myMap)
但是如果你将其用于切片,你会发现切片中的元素不会被删除,只会被清零.
mySlice := []int{1, 2, 3, 4, 5, 6, 7, 8}
fmt.Println(mySlice) //输出为[1 2 3 4 5 6 7 8]
clear(mySlice)
fmt.Println(mySlice) //输出为[0 0 0 0 0 0 0 0]
下面是使用AI生成的复合类型, 注意:如果你有需求,可以回顾这些知识,但是基本上可以跳过.
Go语言中的切片(slice)是一种基于数组的灵活且强大的数据结构,它是对数组的一个引用。切片提供了一种方便的方式来操作和操作集合.
切片有三个关键属性:
切片在声明、初始化、操作和比较方面都比数组更加灵活。你可以使用 make() 函数创建一个切片,使用 append() 函数向切片添加元素,使用 copy() 函数复制切片,还可以使用切片的索引操作获取或修改特定位置的元素.
切片还支持一些内置的方法,如 len() 和 cap() ,分别返回切片的长度和容量。此外,切片是引用类型,传递切片作为参数不会复制整个切片,而只是复制引用,这使得函数能够修改原始数据.
以下是一些关于创建和使用切片的示例代码:
package main
import "fmt"
func main() {
// 创建一个整数数组
a := [5]int{1, 2, 3, 4, 5}
// 创建一个基于数组的切片
s := a[1:3]
fmt.Println(s) // 输出: [2 3]
// 使用make函数创建一个长度为5的切片,初始值为0
m := make([]int, 5)
fmt.Println(m) // 输出: [0 0 0 0 0]
// 使用append函数向切片添加元素
m = append(m, 1, 2, 3)
fmt.Println(m) // 输出: [0 0 0 0 0 1 2 3]
// 使用copy函数复制切片
n := make([]int, len(m))
copy(n, m)
fmt.Println(n) // 输出: [0 0 0 0 0 1 2 3]
// 这里写段
m = append(m[:len(m)-2], m[2:]...)
fmt.Println(m) // 输出: [0 0 3]
}
以上代码展示了切片的基本操作,包括创建、添加元素、复制和删除元素等。切片是Go语言中非常强大且有用的数据结构,可以帮助开发者更高效地处理数据和实现复杂的逻辑.
Go语言中的映射(map)是一种特殊的数据结构,它是一个无序的键值对集合。映射的键必须是唯一的,但值可以重复。映射的元素是键值对,每个键都映射到一个值.
映射的声明使用如下语法:
var m map[keyType]valueType
其中, keyType 是键的类型, valueType 是值的类型.
映射的操作包括:
m[k]
:使用键 k
访问映射,返回对应的值。如果键 k
在映射中不存在,会返回该映射类型的零值。 m[k] = v
:使用键 k
将值 v
赋值给映射。如果键 k
在映射中不存在,会创建一个新的键值对。 delete(m, k)
:删除映射 m
中键为 k
的键值对。 len(m)
:返回映射中键值对的数量。 m[k] == v
或 m[k] != v
:用于判断映射中是否存在某个键 k
,并且其对应的值是否等于 v
。 需要注意的是,映射是引用类型,传递的是引用而不是整个映射的拷贝。因此,对映射的修改会影响原始映射。此外,映射的键必须是唯一的,但值可以重复。映射的元素是无序的,每次迭代时顺序可能不同.
以下是一个使用映射的示例代码:
package main
import "fmt"
func main() {
// 创建一个映射
m := make(map[string]int)
//赋值
m = map[string]int{
"我是水货": 1,
"水货": 2,
"水": 3,
}
// 添加键值对到映射
m["货"] = 4
// 访问映射中的元素
fmt.Println(m["我是水货"]) // 输出: 1
fmt.Println(m["水货"]) // 输出: 2
fmt.Println(m["水"]) // 输出: 3
// 修改映射中的元素
m["水货"] = 10
fmt.Println(m["水货"]) // 输出: 10
// 删除映射中的元素
delete(m, "水")
fmt.Println(m["水"]) // 输出: 0
// 检查映射中是否存在某个键
_, ok := m["水货"]
fmt.Println(ok) // 输出: true
_, ok = m["水"]
fmt.Println(ok) // 输出: false
}
以上代码展示了如何声明、访问、修改和删除映射中的元素,以及如何检查映射中是否存在某个键.
在Go语言中,string是一种内建类型,表示字节的序列。这些字节通常用于表示Unicode字符序列。String是不可变的,也就是说,一旦一个字符串被创建,就不能修改它.
字符串之间可以进行比较操作(==、!=、<、>),而字符串与字节数组之间可以通过 + 号进行拼接,也可以通过 == 进行比较操作。字符串也可以通过使用索引语法 s[i] 获取指定位置的字节,但不可进行修改操作.
Go语言的string类型是不可变的,这意味着你不能修改字符串的内容。如果你需要一个可变的字符串,可以将字符串转换为字节数组([]byte),然后进行修改操作.
在Go语言中,字符串的本质是一个字节数组([]byte)。因此,它们之间可以互相转换。例如,你可以将字符串转换为字节数组,然后对字节数组进行修改,再将修改后的字节数组转换回字符串.
需要注意的是,字符串的长度是固定的,不能进行修改。如果你需要一个可变长度的字符串,可以将字符串转换为切片(slice),然后进行修改操作.
以下是一些关于Go语言string类型的示例代码:
package main
import "fmt"
func main() {
// 声明一个字符串变量
str := "Hello, World!"
// 获取字符串的长度
fmt.Println(len(str)) // 输出: 13
// 将字符串转换为字节数组
bytes := []byte(str)
// 修改字节数组中的某个元素
bytes[0] = 'M'
// 将修改后的字节数组转换回字符串
str = string(bytes)
fmt.Println(str) // 输出: Mello, World!
}
以上代码演示了如何声明一个字符串变量、获取字符串的长度、将字符串转换为字节数组、修改字节数组中的元素,以及将修改后的字节数组转换回字符串.
在Go语言中,字符串底层结构是一个字节序列,其数据结构定义如下:
type stringStruct struct {
str unsafe.Pointer
len int
}
这里, str 是一个指向底层字节数组的指针,而 len 表示字符串的字节长度。这个结构体定义在 runtime/string.go 文件中.
字符串的赋值操作实际上是结构体的复制过程,不包含指针指向的内容的复制。这意味着,字符串是不可变的,一旦初始化后就不能修改。如果你需要一个可变的字符串,可以将字符串转换为字节数组,然后进行修改操作。修改后的字节数组再通过 string() 函数可以转回为字符串.
另外,字符串可以支持切片操作,不同位置的切片底层访问的是同一块内存数据。由于只读的特性,相同字符串面值常量通常对应同一个字符串常量.
需要注意的是,Go语言的字符串底层存储是基于UTF-8编码的。UTF-8是一种可变长度的编码方式,每个字符由1到4个字节组成,具体取决于字符的Unicode码位。在UTF-8编码中,ASCII字符只需要1个字节表示,双字节字符需要2个字节表示,以此类推。因此,对于非ASCII字符的字符串,其长度可能不等于字节长度.
综上所述,Go语言的字符串底层数据结构是一个指向底层字节数组的指针和字符串长度的组合。字符串是不可变的,但可以通过转换为字节数组进行修改。字符串支持切片操作和UTF-8编码.
在Go语言中,可以使用 unsafe 包来转换 string 和 []byte 。 unsafe 包提供了一组函数,可以在不进行边界检查的情况下直接访问内存地址.
要将 string 转换为 []byte ,可以使用 []byte() 类型强转,可以使用 unsafe.Pointer() 函数将字符串的指针转换为字节数组的指针,然后使用 *(*[]byte)(unsafe.Pointer(uintptr)) 进行类型断言.
下面是一个示例代码:
package main
import (
"fmt"
"unsafe"
)
func main() {
str := "Breeze0806"
strPtr := unsafe.Pointer(&str)
bytesPtr := *(*[]byte)(unsafe.Pointer(uintptr(strPtr)))
fmt.Println(bytesPtr)
}
要将 []byte 转换为 string ,可以使用 string() 类型强转,也可以使用以下方式。但是,需要注意的是,如果字节数组包含无效的UTF-8序列,转换后的字符串可能会出现乱码.
下面是一个示例代码:
package main
import (
"fmt"
"unsafe"
)
func main() {
b := []byte{66, 114, 101, 101, 122, 101, 48, 56, 48, 54}
str = *(*string)(unsafe.Pointer(&b))
fmt.Println(str) // Output: Breeze0806
}
需要注意的是,使用 unsafe 包进行类型转换是不安全的,因为它绕过了Go语言的类型检查机制。因此,应该谨慎使用,并确保转换后的数据是正确的.
《使用go语言的数据类型解决leetcode题目》 。
最后此篇关于4.go语言复合类型简述的文章就讲到这里了,如果你想了解更多关于4.go语言复合类型简述的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
做数据分析、科学计算等离不开工具、语言的使用,目前最流行的数据语言,无非是MATLAB,R语言,Python这三种语言,但今天小编简单总结了python语言的一些特点及平常使用的工具等。 为
服务器和应用程序日志记录是开发人员、运维人员和安全团队了解应用程序在其生产环境中运行状态的重要工具。 日志记录使运维人员能够确定应用程序和所需组件是否运行平稳,并检测是否发生了异常情况,以便他们能
了解程序集如何在C#.NET中加载 我们一直在处理库和NuGet软件包。不管是好是坏,高级.NET开发人员都需要了解.NET运行时如何加载程序集。 这些库依赖于其他流行的库,并且有很多共享的
目录 Java注解(annotation)简单上手 1、什么是注解? 2、java内置注解 3、注解的基本运 总结 Java注解(a
系列最后一篇来说说Python中的类与对象,Python这门语言是无处不对象,如果你曾浅要了解过Python,你应该听过Python是一种面向对象编程的语言,所以你经常可能会看到面向“对象”编程这类
tf.reverse_sequence()简述 在看bidirectional_dynamic_rnn()的源码的时候,看到了代码中有调用 reverse_sequence()这一方法,于是又回去
目录 (一)hog特征提取 (二)dlib库 (三)卷积神经网络特征提取(cnn) 人脸图像特征提取方法
代码如下: <?php /* 边学边做的,为方便自己翻阅而发布,更为得到高人指点而发布,欢迎高手指点...... 【提示】本例通过
我是一名优秀的程序员,十分优秀!