Go 编程 | 连载 11 - 复杂数据类型 Slice

简介: Go 编程 | 连载 11 - 复杂数据类型 Slice

一、切片 Slice

Go 语言数组的长度是不可变的,也就无法数组中添加元素,Go 提供了另一种长度可变的数组,既切片(动态数组),切片可以进行追加元素,相比数组来说更加灵活。

切片的定义

第一种定义方式

Go 切片的定义方式与数组非常类似,但是数组定义时需要指定数组长度,而切片定义时则无须指定长度。

func main() {
   // 定义切片
   var langs = []string{"Go", "Python", "Ruby", "Java"}
   framworks := []string{"Rails", "Gin", "Play"}
   fmt.Printf("%T, %T", langs, framworks)
}
复制代码

执行上述代码,输出结果如下:

[]string, []string
复制代码

与数组类型不同的是切片类型并不包含长度属性。

第二种定义方式

使用 make 函数也可以定义切片,make 函数还可以定义 map 以及 channel 数据类型并返回这些数据类型的实例。

func main() {
   // 定义切片
   lans := make([]string, 3)
   fmt.Printf("%T, %v, %v", lans, lans, len(lans))
   lans[0] = "Elixir"
   fmt.Printf("%T, %v, %v", lans, lans, len(lans))
}
复制代码

执行上述代码,输出结果如下:

[]string, [  ], 3
[]string, [Elixir  ], 3
复制代码

make 函数传入两个值,一个是类型,另一个是长度。

使用 make 函数定义切片时,切片中的元素为元素类型的默认值,切片是动态数组,也可以通过索引对元素进行修改。

第三种定义方式

可以通过 切片操作 来获取子数组,子数组的类型就是一个切片类型,这里要注意 切片操作切片类型 的区分。

func main() {
   // 通过数组获取切片
   lans := [3]string{"Elixir", "Scala", "Groovy"}
   // 获取子数组 
   jvm_lans := lans[1:]
   fmt.Printf("%T, %v, %v", jvm_lans, jvm_lans, len(jvm_lans))
}
复制代码

执行上述代码,输出结果如下:

[]string, [Scala Groovy], 2
复制代码

第四种定义方式

func main() {
   // 使用 new 函数定义切片
   webFrameworks := *new([]string)
   fmt.Printf("%T, %v, %v\n", webFrameworks, webFrameworks, len(webFrameworks))
   webFrameworks = append(webFrameworks, "Grails")
   fmt.Printf("%T, %v, %v", webFrameworks, webFrameworks, len(webFrameworks))
}
复制代码

执行上述代码,输出结果如下:

[]string, [], 0
[]string, [Grails], 1
复制代码

new 函数调用时会返回一个内存地址,而 *内存地址 可以获取内存地址指向的实例,append 函数可以对切片进行追加操作,根据输出结果可以确定,初始化时切片的长度为 1,追加一个元素之后切片的长度变为 2。

make 函数和 new 函数都可以定义切片,它们的区别如下:

  • make 和 new 都是用来分配内存的內建函数,且在堆上分配内存,make 即分配内存,也初始化内存;new只是将内存清零,并没有初始化内存。
  • make 返回的还是引用类型(实例)本身;而 new 返回的是指向类型的指针(内存地址)。
  • make 只能用来分配及初始化类型为 slice,map,channel;new 可以分配任意类型的数据。

切片是引用类型

数组是值类型,而切片是引用类型,同样可以通过在自定义函数中修改传入的切片类型的数据来验证切片是引用类型。

func main() {
   lans := []string{"Elixir", "Scala", "Ruby"}
   SliceHandler(lans)
   fmt.Println(lans)
}
func SliceHandler(sli []string) {
   fmt.Println(sli)
   for idx, item := range sli {
      sli[idx] = strings.ToUpper(item)
   }
   fmt.Println(sli)
}
复制代码

执行上述代码,输出结果如下:

[Elixir Scala Ruby]
[ELIXIR SCALA RUBY]
[ELIXIR SCALA RUBY]
复制代码

原切片中的元素被修改,说明切片是引用类型。

二、切片的操作

追加

切片的追加操作可以通过内置的 append 函数实现,该函数需要传入要追加的切片以及要追加的元素,可以追加一个元素,也可以追加多个元素。

func main() {
   lans := []string{"Elixir", "Scala", "Ruby"}
   fmt.Printf("%T, %v, %v\n", lans, lans, len(lans))
   lans = append(lans, "Groovy")
   fmt.Printf("%T, %v, %v\n", lans, lans, len(lans))
   lans = append(lans, "Python", "Go", "Java")
   fmt.Printf("%T, %v, %v\n", lans, lans, len(lans))
}
复制代码

执行上述代码,输出结果如下:

[]string, [Elixir Scala Ruby], 3
[]string, [Elixir Scala Ruby Groovy], 4
[]string, [Elixir Scala Ruby Groovy Python Go Java], 7


相关文章
|
10月前
|
设计模式 缓存 算法
Go如何进行高质量编程与性能调优实践
本文介绍了Go语言高质量编程与性能调优的实践方法。高质量编程包括良好的编码习惯(如清晰注释、命名规范)、代码风格与设计(如MVC模式)、简洁明了的代码原则,以及单元测试与代码重构的重要性。性能调优方面,涵盖算法优化、数据结构选择、I/O优化、内存管理、并行与并发处理优化及代码层面的改进。通过这些方法,可有效提升代码质量和系统性能。
194 13
|
10月前
|
分布式计算 Go C++
初探Go语言RPC编程手法
总的来说,Go语言的RPC编程是一种强大的工具,让分布式计算变得简单如同本地计算。如果你还没有试过,不妨挑战一下这个新的编程领域,你可能会发现新的世界。
243 10
|
10月前
|
人工智能 Go
[go]Slice 切片原理
本文详细介绍了Go语言中的切片(slice)数据结构,包括其定义、创建方式、扩容机制及常见操作。切片是一种动态数组,依托底层数组实现,具有灵活的扩容和传递特性。文章解析了切片的内部结构(包含指向底层数组的指针、长度和容量),并探讨了通过`make`创建切片、基于数组生成切片以及切片扩容的规则。此外,还分析了`append`函数的工作原理及其可能引发的扩容问题,以及切片拷贝时需要注意的细节。最后,通过典型面试题深入讲解了切片在函数间传递时的行为特点,帮助读者更好地理解和使用Go语言中的切片。
313 0
|
存储 编译器 Go
go语言中的变量、常量、数据类型
【11月更文挑战第3天】
172 9
|
数据采集 监控 Java
go语言编程学习
【11月更文挑战第3天】
274 7
|
数据库连接 Go 数据库
Go语言中的错误注入与防御编程。错误注入通过模拟网络故障、数据库错误等,测试系统稳定性
本文探讨了Go语言中的错误注入与防御编程。错误注入通过模拟网络故障、数据库错误等,测试系统稳定性;防御编程则强调在编码时考虑各种错误情况,确保程序健壮性。文章详细介绍了这两种技术在Go语言中的实现方法及其重要性,旨在提升软件质量和可靠性。
253 1
|
Unix Linux Go
go进阶编程:Golang中的文件与文件夹操作指南
本文详细介绍了Golang中文件与文件夹的基本操作,包括读取、写入、创建、删除和遍历等。通过示例代码展示了如何使用`os`和`io/ioutil`包进行文件操作,并强调了错误处理、权限控制和路径问题的重要性。适合初学者和有经验的开发者参考。
280 4
|
存储 数据采集 缓存
为什么 Go map 和 slice 是非线程安全的?
为什么在 Go 语言里,map 和 slice 不支持并发读写,也就是是非线程安全的,为什么不支持? 见招拆招后,紧接着就会开始讨论如何让他们俩 ”冤家“ 支持并发读写?
720 0
为什么 Go map 和 slice 是非线程安全的?
|
5月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
301 1
|
7月前
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
436 1