GO语言基础(下)

简介: GO语言基础(下)

四、常用结构


1、内置函数、闭包

  1. close:主要用来关闭channel
  2. len:用来求长度,比如string、 array、 slice、 map、 channel
  3. new:用来分配内存,主要用来分配值类型,比如int、 struct。返回的是指针
  4. make:用来分配内存,主要用来分配引用类型,比如chan、 map、 slice
  5. append:用来追加元素到数组、 slice中
  6. panic和recover:用来做错误处理


闭包:一个函数和与其相关的引用环境组合而成的实体

package main
import "fmt"
func Adder() func(int) int {
  var x int//只初始化一次
  return func(delta int) int {
    x += delta
    return x
  }
}
//上述代码类似于cpp中在类中定义成员x,func函数对x进行+delta
func main() {
  var f = Adder()
  fmt.Println("1:", f(1))//0
  fmt.Println("2:", f(20))//21
  fmt.Println("3:", f(300))//321
}


2795ab0f699921dc7d1bb165ffd49194.png

2、数组与切片

数组:是同一种数据类型的固定长度的序列

数组定义: var a [len]int,比如: var a[5]int 一旦定义,长度不能变

长度是数组类型的一部分,因此, var a[5] int和var a[10]int是不同的类型

访问越界,如果下标在数组合法范围之外,则触发访问越界,会panic

数组是值类型,因此参数传递改变的是副本的值,不会改变本身的值

数组初始化及遍历:

0dbaac557ac27f1cc4d8712266efb273.png

多维数组及遍历:

var age [5][3]int
var f [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}
for k1, v1 := range f {
    for k2, v2 := range v1 {
        fmt.Printf("(%d,%d)=%d ", k1, k2, v2)
    }
    fmt.Println()
}


切片定义:

切片:切片是数组的一个引用,因此切片是引用类型

切片的长度可以改变,因此, 切片是一个可变的数组

切片遍历方式和数组一样,可以用len()求长度

cap可以求出slice最大的容量, 0 <= len(slice) <= (array), 其中array是slice引用的数组

make创建切片:

slice := make([]type, len)
slice := make([]type, len, cap)

afb8db963d96073a439078923ef70715.png

切片初始化:

var slice1 []int = arr[start:end]//包含start到end之间的元素,但不包含end,[start,end)
var slice2 []int = arr[0:end]//可以简写为 var slice []int=arr[:end]
var slice3 []int = arr[start:len(arr)]//可以简写为 var slice[]int = arr[start:]
var slice4 []int = arr[0, len(arr)]//可以简写为 var slice[]int = arr[:]
Slice = slice[:len(slice)-1] //最后一个元素去掉 


7286093db01c3e5881cc72867b42bca4.png

切片的内存布局,类似C++ vector:

c4c83cbb8577f60030fc8bf5b0c30271.png

用append内置函数操作切片:

slice := make([]int, 10)
slice=append(slice, 10)//增添元素,更新
var a = []int{1, 2, 3}
var b = []int{4, 5, 6}
a = append(a, b...)//增添数组


For range 遍历切片:

for index, val := range slice {
}


切片resize:

var a = []int {1,3,4,5}
b := a[1:2]
b = b[0:3]


切片拷贝:

s1 := []int{1,2,3,4,5}
s2 := make([]int, 10)
copy(s2, s1)


string与slice:

string底层就是一个byte的数组,因此,也可以进行切片操作

str := “hello world”
s1 := str[0:5]
fmt.Println(s1)
s2 := str[5:]
fmt.Println(s2)  
s := []byte(str)//修改str
s[0] = ‘o’
str = string(s)  


string的底层布局:

54134b817fa1516bc4d5d355e9de4751.png

数组和切片的区别:

数组:类型 [n]T 表示拥有 n 个 T 类型的值的数组,指定空间大小

切片:类型 []T 表示一个元素类型为 T 的切片(动态开辟数组),不指定大小

new和make的区别:

var i *int=new(int)
*i=10
var num []int = make([]int, 10)
num[1]=10


make也是用于内存分配的,但是和new不同,它只用于chan、 map以及切片的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了


3、map

map是一种特殊的数据结构:一种元素对 (pair) 的无序集合,pair 的一个元素是 key,对应的另一个元素是 value,所以这个结构也称为关联数组或字典。这是一种快速寻找值的理想结构:给定 key,对应的 value 可以迅速定位。

map是引用类型,可以使用如下声明:

var map1 map[keytype]valuetype
var map1 map[string]int


key 可以是任意可以用 == 或者 != 操作符比较的类型,比如 stringintfloat32(64)。所以数组、切片和结构体不能作为 key ,但是指针和接口类型可以。如果要用结构体作为 key 可以提供Key()Hash() 方法,这样可以通过结构体的域计算出唯一的数字或者字符串的 key

value 可以是任意类型的;通过使用空接口类型,我们可以存储任意值,但是使用这种类型作为值时需要先做一次类型断言

map引用类型 的: 内存用 make() 方法来分配

map 的初始化:

var map1 = make(map[keytype]valuetype)


你错误地使用 new() 分配了一个引用对象,你会获得一个空引用的指针

测试 map1 中是否存在 key1

if _, ok := map1[key1]; ok {
  // ...
}


map1 中删除 key1

delete(map1, key1)


注:如果 key1 不存在,该操作不会产生错误

使用 for 循环读取 map

for key, value := range map1 {
  ...
}


只想获取 key

for key := range map1 {
  fmt.Printf("key is: %d\n", key)
}


注意 map 不是按照 key 的顺序排列的,也不是按照 value 的序排列的

如果你想为 map 排序,需要将 key(或者 value)拷贝到一个切片,再对切片排序(使用 sort 包),然后可以使用切片的 for-range 方法打印出所有的 key 和 value

package main
import (
  "fmt"
  "sort"
var (
  barVal = map[string]int{"alpha": 34, "bravo": 56, "charlie": 23,
              "delta": 87, "echo": 56, "foxtrot": 12,
              "golf": 34, "hotel": 16, "indio": 87,
              "juliet": 65, "kili": 43, "lima": 98}
)
func main() {
  fmt.Println("unsorted:")
  for k, v := range barVal {
    fmt.Printf("Key: %v, Value: %v / ", k, v)
  }
  keys := make([]string, len(barVal))
  i := 0
  for k, _ := range barVal {
    keys[i] = k
    i++
  }
  sort.Strings(keys)
  fmt.Println()
  fmt.Println("sorted:")
  for _, k := range keys {
    fmt.Printf("Key: %v, Value: %v / ", k, barVal[k])
  }
}


五、Go中包及go mod


1、go mod

实际项目开发中我们首先要在我们项目目录中用go mod命令生成一个go.mod文件管理我们项目的依赖

使用go mod命令生成一个go.mod文件

go mod init goProject


生成一个 go.mod 的文件,里面的内容是go版本,以及以后添加的包

module goProject
go 1.14


2、包

包(package)是多个Go源码的集合,一个包可以简单理解为一个存放多个.go文件的文件夹。该文件夹下面的所有go文件都要在代码的第一行添加如下代码,声明该文件归属的包

package 包名


注意事项

  • 一个文件夹下面直接包含的文件只能归属一个package,同样一个package的文件不能在多个文件夹下。
  • 包名可以不和文件夹的名字一样,包名不能包含-符号。
  • 包名为main的包为应用程序的入口包,这种包编译后会得到一个可执行文件,而编译不包含main包的源代码则不会得到可执行文件。


3、init()初始化函数

在Go 语言程序执行时导入包语句会自动触发包内部init()函数的调用。

需要注意的是:init() 函数没有参数也没有返回值。init()函数在程序运行时自动被调用执行,不能在代码中主动调用它。

包初始化顺序:


依赖

使用go mod命令生成一个go.mod文件

go mod init goProject


生成一个 go.mod 的文件,里面的内容是go版本,以及以后添加的包

module goProject
go 1.14


2、包

包(package)是多个Go源码的集合,一个包可以简单理解为一个存放多个.go文件的文件夹。该文件夹下面的所有go文件都要在代码的第一行添加如下代码,声明该文件归属的包

package 包名


注意事项

  • 一个文件夹下面直接包含的文件只能归属一个package,同样一个package的文件不能在多个文件夹下。
  • 包名可以不和文件夹的名字一样,包名不能包含-符号。
  • 包名为main的包为应用程序的入口包,这种包编译后会得到一个可执行文件,而编译不包含main包的源代码则不会得到可执行文件。


3、init()初始化函数

在Go 语言程序执行时导入包语句会自动触发包内部init()函数的调用。

需要注意的是:init() 函数没有参数也没有返回值。init()函数在程序运行时自动被调用执行,不能在代码中主动调用它。

包初始化顺序:

[外链图片转存中…(img-jR5UCw7D-1698326264819)]

[外链图片转存中…(img-OPYWhU6s-1698326264819)]

相关文章
|
5天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
23 2
|
9天前
|
JavaScript Java Go
探索Go语言在微服务架构中的优势
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出。本文将深入探讨Go语言在构建微服务时的性能优势,包括其在内存管理、网络编程、并发模型以及工具链支持方面的特点。通过对比其他流行语言,我们将揭示Go语言如何成为微服务架构中的一股清流。
|
3天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
11 2
|
3天前
|
Go C++
go语言中的条件语句
【11月更文挑战第4天】
14 2
|
8天前
|
Ubuntu 编译器 Linux
go语言中SQLite3驱动安装
【11月更文挑战第2天】
30 7
|
8天前
|
关系型数据库 Go 网络安全
go语言中PostgreSQL驱动安装
【11月更文挑战第2天】
38 5
|
8天前
|
安全 Go
用 Zap 轻松搞定 Go 语言中的结构化日志
在现代应用程序开发中,日志记录至关重要。Go 语言中有许多日志库,而 Zap 因其高性能和灵活性脱颖而出。本文详细介绍如何在 Go 项目中使用 Zap 进行结构化日志记录,并展示如何定制日志输出,满足生产环境需求。通过基础示例、SugaredLogger 的便捷使用以及自定义日志配置,帮助你在实际开发中高效管理日志。
25 1
|
7天前
|
程序员 Go
go语言中的控制结构
【11月更文挑战第3天】
84 58
|
6天前
|
监控 Go API
Go语言在微服务架构中的应用实践
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出,成为构建微服务的理想选择。本文将探讨Go语言在微服务架构中的应用实践,包括Go语言的特性如何适应微服务架构的需求,以及在实际开发中如何利用Go语言的特性来提高服务的性能和可维护性。我们将通过一个具体的案例分析,展示Go语言在微服务开发中的优势,并讨论在实际应用中可能遇到的挑战和解决方案。
|
7天前
|
存储 编译器 Go
go语言中的变量、常量、数据类型
【11月更文挑战第3天】
25 9