在上一篇笔记中记录了Go语言的简介,优势,入门语法和基础语法。在本篇笔记中继续叙述Go语言的语法。
2.6 字符串
Go 语言的字符串使用 UTF8 编码,且采用byte数组存储。
str1 := "Golang"
str2 := "Go语言"
fmt.Println(reflect.TypeOf(str1[2]).Kind()) // 输出 uint8
fmt.Printf("%d %c\n", str2[2], str2[2])
通过reflect.TypeOf().Kind()可以获取到变量的类型,即为UTF8,然后通过 str1[2] 的随机读取方法也可确定是数组存储,同时通过分析 str2[2] 值非语字可以确定为 byte 数组存储,因为在Go语言中中文占 3 byte。
以下英文和中文占位情况:
- 英文每个字符占 1 byte
- 中文每个文字占 3 byte
2.7 数组 array
与声明变量写法类似,在Go语言中声明数组或是在声明时同时初始化写法为:
var arr1 [10]int // 一维数组
var arr2 [10][10]int // 二维数组
var arr3 = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} //初始化
arr4 := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} //简略写法
与其它语言一样,使用 [] 索引。
数组长度不能改变,所以在Go语言中通常使用且切片。
2.8 切片 slice
切片不同于数组,切片可以认为是数组的抽象,其底层为数组,包含三个要素:容量,长度和指向底层数组的指针。
切片可以随时进行扩展,可以任意更改长度。可以用 make 来创建一个切片,使用[]来索引,使用 append 来添加元素。以下为实例:
slice1 := make([]string, 3) //长度为3的切片
slice2 := make([]string, 3, 5) // 长度为 3 容量为 5 的切片 fmt.Println(len(slice2), cap(slice2)) // 3 5
slice1[0] = "a"
slice1[1] = "b"
slice1[2] = "c"
fmt.Println(s[2])
slice1 = append(slice1, "d")
slice1 = append(slice1, "e", "f")
fmt.Println(len(slice2), cap(slice2)) //6
执行 append 的时候,如果容量不够,会扩容并目返回新的 sIice, 所以在写法上是赋值写法. slice 也可以执行切片。如下所示:
//切片
sub1 := slice1[3:] // [d e f]
sub2 := slice1[:3] // [a b c]
sub3 := slice1[1:3] // [b c d]
// 合并切片
combined := append(sub1, sub2, sun3)
2.9 哈希/字典 map
map是使用非常频繁的数据结构,类似于 java 的 HashMap,为键值对形式。
// 声明
map1:= make(map[string]int)
map1["one"] = 1
map1["two"] = 2
fmt.Println(map1)
fmt.Println(len(map1))
r, ok := map1["unknow"]
fmt.Println(r, ok) //0 false
delete(map1, "one"0
// 声明时初始化
map2 := map[string]string{
"Name": "lorenzo",
"Age": "22",
}
//
map2["Age"] = 20
2.10 指针
Go语言的指针与C语言一样,代表值的地址,用 *标识,对变量取地址用&标识。
指针通常在函数传递参数,或者给类型定义新的方法时使用。
str := "Golang"
var p *string = &str // p 是指向 str 的指针
*p = "Go语言"
fmt.Println(str) // Go语言
3. 函数 Function
3.1 基本形式
与其他语言一样,函数主体为关键字func, 函数名,传入参数,返回值。其中传入参数可以有多个,返回值也可以有多个。在业务逻辑开发中函数一般返回两个值,一个为结果,一个为错误信息。以下为示例:
func add(num1 int, num2 int) int {
return num1 + num2
}
func div(num1 int, num2 int) (int, int) {
return num1 / num2, num1 % num2
}
func rid(num1 int, num2 int) (ans int) {
ans = num1 * num2 //给返回值命名,简写 return
return
}
func main() {
r1, r2 := div(200, 100)
fmt.Println(r1, r2)
fmt.Println(add(100, 200))
}
3.2 错误处理
不同于 Java 的异常, Go 语言使用一个单独的返回值来传递错误信息。
如果函数可能出现错误,可以在函数的返回值类型里面,后面加一个 error 。如果函数实现过程中,如果出现不能处理的错误,可以返回给调用者处理。函数调用成功,error 的值是 nil,调用失败,通过 error 知道具体的错误信息。
- 可以通过
error.News返回自定义错误 - 不可预知的错误,例如数组越界。该类型错误可能会导致程序非正常退出,Go 语言称该类型为
panic。 - 与 Java try---catch机制类似, go语言使用
defer和recover defer定义了异常处理的函数,在协程退出前,会执行完defer的任务。若函数触发panic, 则执行defer0defer中,使用recover,使程序恢复正常,并且将返回值设置为-1。可以不处理返回值,默认值0。
func GetNum(index int) (ret int) {
if index < 0 {
return errors.New("error: index is -")
}
defer func() {
if r := recover(); r != nil {
fmt.Println("error happened!", r)
ret = -1
}
}()
nums := [3]int{1, 2, 3}
return nums[index]
}
func main() {
fmt.Println(GetNum(100))
}
4. 结构体 struct
Go语言的结构体与Java的类Class类似,在结构体中可以定义多个字段, 给结构体实现方法等。
- 创建 Student 的实例,字段不需要都赋值,没有赋值的变量被赋予默认值。
type Student struct {
StuId int
Name string
Gender string
Age int
Grade string
Class int
}
- 实现方法,在
func和函数名之间,加上该方法对应的实例名stu及其指针类型*Student,可以通过实例名访问该实例的字段和其他方法。调用方法通过实例名.方法名(参数)的方式。
func (stu *Student) SearchStudentInfoByName(name string) string {
return fmt.Sprintf("id is %d, name is %s, gender is %s, age is %d , grade is %s,, class is %d", stu.StuId, stu.Name, stu.Gender, stu.Age, stu.Grade, stu.Class)
}
func main() {
stu := &Student{
StuId: 1,
Name: "lorenzo",
Gender: "boy",
Age: 22,
Grade: "Fir",
Class: 1,
}
msg := stu.SearchStudentInfoByName("stu.Name")
fmt.Println(msg)
}
- 还可以使用
new实例化
func main() {
stu2 := new(Student)
fmt.Println(stu2.SearchStudentInfoByName(""))
}
5. 接口 Interface
接口是定义了一组方法的集合,接口不能被实例化,一个类型可以实现多个接口。
- Go 语言中,不需要显式地声明实现接口,直接实现该接口对应的方法即可。
type Person interface {
getName() string
}
type Student struct {
name string
}
func (stu *Student) getName() string {
return stu.name
}
type Teacher struct {
name string
}
func (t *Teacher) getName() string {
return t.name
}
func main() {
var p Person = &Student{
name: "lorenzo",
age: 22,
}
fmt.Println(p.getName())
}
- 实例化
Student后,强制类型转换为接口类型Person,且须实现该接口全部方法。
如果定义了一个没有任何方法的空接口,那么这个接口可以表示任意类型
func main() {
m := make(map[string]interface{})
m["name"] = "lorenzo"
m["age"] = 22
m["courses"] = [3]string{"math", "chinese", "english"}
fmt.Println(m) // map[ name:lorenzo age:22 courses:[math chinese english]]
}
6. Go语言基础语法快速上手结篇语
在学习Go语言的字符串、数组、切片、map、结构体、接口、函数、错误处理以及标准库的过程中,我深刻体会到了Go语言的简洁、高效和强大之处。
首先,Go语言的字符串处理非常方便,提供了丰富的字符串操作方法,使得处理文本数据变得简单而高效。数组和切片的灵活性让我可以轻松地处理集合数据,而map则提供了便捷的键值对存储和访问方式,非常适用于构建复杂的数据结构。
在面向对象方面,Go语言的结构体和接口机制让我能够更好地组织和抽象代码,实现高内聚、低耦合的设计。结构体可以封装数据和行为,而接口则定义了对象的行为规范,使得代码更加灵活和可扩展。
函数是Go语言的核心,它的简洁、灵活和高效执行使得代码编写和调试变得更加轻松。错误处理机制让我能够更好地处理异常情况,保证程序的健壮性和可靠性。
通过学习这些内容,我深刻认识到Go语言的优势和魅力。它的简洁、高效和并发性能使得它成为构建高并发、可扩展的后端系统的理想选择。我对未来能够运用Go语言构建出更加高效、可靠的应用程序充满了信心。我期待继续深入学习Go语言,探索更多的应用场景和技术,不断提升自己的编程能力。
下一篇见!