Go语言的基础语法
包
使用包的原因:
- 模块化和代码组织:包提供了一种模块化的方式来组织代码。将相关的函数、类型和变量放在同一个包中,可以提高代码的可读性、可维护性和重用性。包结构可以帮助开发者更好地组织和管理项目中的代码。
- 封装和信息隐藏:包可以通过封装隐藏内部实现细节,只暴露必要的接口给外部使用。这样可以保护代码的私密性,防止其他代码直接访问和修改包的内部状态,提供了一种信息隐藏的机制。
- 名称空间和标识符冲突解决:使用包可以创建独立的命名空间,防止不同包中的标识符冲突。包名加上访问符号
.或者包别名的方式,可以访问其他包中的代码,避免了全局命名冲突的问题。 - 代码复用和共享:包可以作为一个可重用的模块被其他程序引用和使用。通过导入其他的包,我们可以使用其中的函数、变量和类型,避免了重复编写相同的代码,提高了编码效率。
- 分布式开发和团队协作:包的使用方便了分布式开发和团队协作。不同的开发者可以独立地编写和管理各自的包,并通过版本管理工具将其集成到一个项目中。这样就可以高效地开发大型项目或团队协作,每个人负责一个或多个包的开发。
- 代码可维护性:将代码以包的形式组织起来,可以提高代码的可维护性。包可以分解复杂的问题为更小的子问题,让代码更易于理解、测试和修改。代码的职责划分清晰,修改一个包不会对其他包产生意外的影响。
包的声明
package main//1.进行包的声明,建议:声明这个包的和所在的文件夹同名
//2.main包是程序的入口包,一般main函数会放在这个包下
// 3.然后在代码中通过 import 关键字引入包,就可以使用其中的功能了:
import (
"fmt"
"mycode/text" //包名从$GOPATH/src/后开始计算的,使用/进行路径分隔
)
func Myfunc(){ //大写字母开头的函数可以被其它包引用
}
func main(){
//引用其它包的函数 包名+.+函数名
fmt.Println("Hello world")
text.Text()
}
闭包
- 什么是闭包
闭包就是和其相关的引用环境组成的整体。 - 案例展示
package main
import "fmt"
// 函数求值
func getSum() func(int) int {
var sum int = 0
return func(num int) int {
sum = sum + num
return sum
}
}
// 闭包: 返回的匿名函数 + 匿名函数以外的变量num
// 匿名函数中的变量会一直保存在内存中, 可以一直使用
func main() {
f := getSum()
fmt.Println(f(1)) // sum = 0 + 1 = 2
fmt.Println(f(2)) // sum = 1 + 2 = 3
fmt.Println(f(3)) // sum = 3 + 3 = 6
}
- 闭包的本质
闭包的本质依旧是一个匿名函数,只是这个函数引入外界的变量/参数
匿名函数+引用的变量/参数 = 闭包 - 特点
(1) 返回的是一个匿名函数,但是这个匿名函数引用的函数外的变量/参数,因此这个匿名函数就和变量/参数形成一个主题,构成闭包。
(2) 闭包中使用的变量/参数会一直保存在内存中,所以会一直使用——>意味着闭包不能滥用
常用字符串操作
- 字符串长度
len(str) - 字符串遍历
//方式一
for i, value := range str{
fmt.Printf("%d",i)
fmt.Printf("%c",value)
fmt.Printf("索引%d 字母为%c",i,value)
//对str进行遍历 ,遍历索引被i接收,结果数值被value接收
}
//方式二 利用r := []rune(str) 将字符串转为切片
r := []rune(str)
for i := 0 ; i < len(r) ; i ++{
fmt.Printf("%c",r[i])
}
- 字符串转数字
n,err := strconv.Atoi("66") // a to i - 数字转字符串
str := strconv.ltoa(12345) // i to a - 查找子串是否在字符串中
strings.Contains("abcde","abc") - 统计一个字符串有几个指定的子串
count := strings.Count("abcabcabc","abc") - 返回一个子串在字符串第一次出现的索引,没有返回-1
index := strings.Index("abcdef","cd") - 字符串替换
str := stringsReplace("gogogo", "golang", n ) // n是替换n个 n=-1 替换所有 - 去掉字符串左右指定字符
strings.Trim("~abc~","~") //去掉左右
strings.TrimSpace(" abc ","~") // 去掉空格
strings.TrimRight("~abc~","~") //去掉右边
strings.TrimLeft("~abc~","~") //去掉左边
数组
定义 var arr [n]数据类型
遍历 for i := 0 ; i < len(arr) ; i++
切片
在Go语言中,Slice(切片)是一种动态数组的抽象类型。它提供了对数组的某个连续片段的引用,可以按需动态增长和缩减。
Slice 的声明和使用方式如下:
var slice []T // 声明一个切片变量,T代表切片中元素的类型
slice := []T{1, 2, 3} // 声明一个切片并初始化
**
其中,T 表示切片中元素的类型,可以是任意的数据类型。
创建切片有两种方式:
-
从现有的数组或切片中创建切片:可以通过
array[start:end]或slice[start:end]的方式创建一个切片,切片包含了从索引start到end-1的元素。例如:array := [5]int{1, 2, 3, 4, 5} slice := array[1:3] // 创建从索引1到2的切片,结果为[2, 3]**
-
使用内置的
make函数创建切片:可以使用make函数创建指定长度和容量的切片。长度是切片中已经使用的元素个数,容量是底层数组中可供切片使用的元素个数。例如:slice := make([]int, 3, 5) // 创建一个长度为3,容量为5的切片**
make([]T, length, capacity)创建了一个初始长度为length,容量为capacity的切片。
切片有以下几个重要的属性和方法:
len(slice):获取切片的长度。cap(slice):获取切片的容量。slice[index]:访问切片中指定索引的元素。slice[start:end]:获取从索引start到end-1的子切片。append(slice, element):在切片末尾追加元素,并返回新的切片。copy(destSlice, srcSlice):将源切片中的元素拷贝到目标切片中。
切片是引用类型,它们在底层引用了一个数组,并且可以自动扩容。当切片容量不足以存储新的元素时,底层数组会自动扩展以适应新的元素。切片的长度和容量可以通过内置函数 len() 和 cap() 来获取。
切片提供了一种方便且灵活的方式来处理变长的数据集合,广泛应用于Go语言中。它们经常用于动态存储和操作数据,特别是在需要经常改变大小的情况下。
map
在Go语言中,Map(映射)是一种无序的键值对集合,也被称为字典或关联数组。Map中的键(key)和值(value)可以是任意类型,键必须是唯一的。
你可以通过以下方式声明和初始化一个Map变量:
var m map[keyType]valueType // 声明一个Map变量
m := make(map[keyType]valueType) // 使用make函数创建一个Map
m := map[keyType]valueType{key: value, ...} // 声明并初始化一个Map
**
其中,keyType 和 valueType 分别表示键和值的类型,可以是任意类型。使用 make 函数创建Map时,需要指定键值类型。
Map的常见操作包括:
-
插入键值对:可以使用
mapName[key] = value的方式插入键值对。如:m := make(map[string]int) m["apple"] = 1 m["orange"] = 2**
-
获取值:可以通过
mapName[key]的方式获取对应的值。如:fmt.Println(m["apple"]) // 输出:1**
-
删除键值对:可以使用内置的
delete函数删除指定的键值对。如:delete(m, "apple")**
-
判断键是否存在:可以通过以下方式判断键是否存在:
value, ok := m[key] if ok { // 键存在,执行相关操作 } else { // 键不存在 }**
-
遍历Map:可以使用
range关键字遍历Map中的所有键值对。如:for key, value := range m { // 处理每个键值对 }**
Map是一种引用类型,存储的是对底层数据结构的引用。Map的大小不固定,可以根据需要动态增长。它是一种高效的数据结构,可以用于快速查找和索引。
struct
在Go语言中,struct(结构体)是一种用户定义的复合类型,用于表示一组相关的字段(属性)的集合。结构体可以包含不同类型的字段,并且可以根据需要自定义。
你可以通过以下方式声明和使用一个结构体:
type Person struct {
Name string
Age int
City string
}
// 创建结构体实例并初始化
person := Person{Name: "Alice", Age: 25, City: "New York"}
// 访问结构体字段
fmt.Println(person.Name) // 输出:Alice
fmt.Println(person.Age) // 输出:25
fmt.Println(person.City) // 输出:New York
**
在结构体中,字段的类型在冒号后面声明,字段名在冒号前面声明。可以使用点运算符 . 来访问结构体中的字段。
结构体的字段可以包括任何合法的Go类型,包括内置类型、自定义类型、数组、切片、Map等。而且结构体类型可以嵌套其他结构体类型,形成更复杂的数据结构。
结构体的常见操作包括:
- 实例化和初始化:声明结构体类型后,可以通过结构体字面量或赋值语句对结构体进行初始化。
- 访问字段:通过使用点运算符
.可以访问结构体实例中的字段,可以读取和修改字段的值。 - 嵌入结构体:可以在一个结构体中嵌入另一个结构体,以形成更复杂的数据结构。
- 比较结构体:可以使用
==运算符对结构体进行逐个字段的比较。 - 指针与结构体:可以使用指针来操作结构体,通过指针可以直接修改结构体的字段值。
- 方法与结构体:可以为结构体定义方法,结构体方法是一种关联到结构体类型的函数。
结构体是Go语言中常用的一种数据结构,它被广泛用于表示自定义类型、数据模型、数据库映射等。通过结构体,可以组织和管理更复杂的数据,并在代码中进行高效地访问和处理。
结构体方法 Go语言中的方法被定义在结构体类型上,语法格式如下:
func (接收者 Receiver类型) 方法名(参数列表) 返回值列表 {
// 方法体
}
**
其中,接收者可以是类型名加上*或者T,表示指针接收者或值接收者。
- 值接收者:方法接收的是类型的一份副本,修改副本不会影响原始值。
- 指针接收者:方法接收的是类型的指针,可以修改指针指向的原始值。
例子:
type Rectangle struct {
width, height float64
}
// 值接收者的方法
func (r Rectangle) Area() float64 {
return r.width * r.height
}
// 指针接收者的方法
func (r *Rectangle) Scale(scaleFactor float64) {
r.width *= scaleFactor
r.height *= scaleFactor
}
**
调用方法的语法为 实例.方法名(),或者通过指针调用方法的语法为 指针.方法名()。
例子:
r := Rectangle{width: 5, height: 10}
fmt.Println(r.Area()) // 输出:50
p := &r
p.Scale(2)
fmt.Println(r.width) // 输出:10
fmt.Println(r.height) // 输出:20