Go语言基础语法快速上手(二)|青训营

88 阅读7分钟

在上一篇笔记中记录了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, 5678910} //初始化
arr4 := [10]int{1, 2, 3, 4, 5678910} //简略写法

与其它语言一样,使用 [] 索引。 数组长度不能改变,所以在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语言使用 deferrecover
  • defer 定义了异常处理的函数,在协程退出前,会执行完 defer 的任务。若函数触发panic, 则执行 defer0
  • defer 中,使用 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语言,探索更多的应用场景和技术,不断提升自己的编程能力。

下一篇见!