Go语言基础语法 | 青训营笔记

82 阅读10分钟

初识Go语言 青训营笔记第一课

这是我参与【第五届青训营】伴学笔记创作活动的第1天

什么是Go语言?

Go(The Google Programming Language)语言是谷歌2009年发布的第二款开源编程语言,是一种静态型、编译型并自带垃圾回收和并发的编程语言。 Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全、支持并行进程。Go支持面向对象,而且具有真正的闭包(closures)和反射 (reflection)等功能。

Go语言特点:

高性能、高并发:语言性能上和java相近,go语言的并发基于goroutine,类似于线程,但并非线程,可以理解为一种虚拟线程。go语言运行时会合理参与调度goroutine,并将goroutine合理分配到各个cpu中,最大限度地使用cpu性能

语法简单、学习曲线平缓:与c、java语言相似

丰富的标准库,涵盖网络、系统、加密、编码、图形等方面

完善的工具链:Go语言里面内置了很多工具链,最好的应该是gofmt工具,自动化格式化代码

静态链接:在默认情况下是静态链接

快速编译:go语言利用自己的特性实现并发编译,最开始并发编译的最小元素是包,后来是函数,整体编译速度提高

跨平台:Go引用了plan9的代码

垃圾回收:内置runtime,支持垃圾回收,这属于动态语言的特性之一

Go语言的基础语言

2.1 基础语法-helloworld

package main

import "fmt"

func main() {
	fmt.Println("hello world!")
}

main主函数类似于c语言中的int main(),Go语言同时存在函数和方法,fmt.Println()类似于java中的System.out.println()。将一段数据打印在标准输出流中。

在Go语言中;不是必要的,不用每行末添加;

Println中的p是大写的,在Go语言中,函数或方法首字母大写意味着可被其他包调用,否则只能在该包被调用。

2.2 基础语法-变量

Go语言的变量类型是后置的,这样创建一个类型为int的变量:

var a int=2

也可同时声明多个变量:

var b, c int = 1, 2

Go语言支持变量类型自动推断,类型可以省略:

var d = true

也可显示变量类型:

var e float64    //浮点值的默认类型为float64

可以:=简化来声明变量

f :=1

最后使用const关键字来创建常量:

const h = 500   //const无法确定类型,根据上下文自动确定类型

2.3 基础语法-if-else

package main

import "fmt"

func main() {
	if 7%2 == 0 {
		fmt.Println("7 is elen")
	} else {
		fmt.Println("7 is odd")
	}
}

if后不像其他语言加上括号,在括号中写入表达式,Go语言可以不写括号

2.4 基础语法-for循环

-Go语言中只有for循环

for n := 2; n < 5; n++ {
		if n%2 == 0 {
			continue
		} else {
			fmt.Println(n)
		}
	}

和if一样,在for后不用加括号,但是分号不要省略,一定要记住

2.5 基础语法-switch

默认不用加break

a := 3
	switch a {
	case 1:
		fmt.Println("one")
	case 2:
		fmt.Println("two")
	case 3:
		fmt.Println("three")
	default:
		fmt.Println("other")
	}

2.6 基础语法-数组

var c [2][3]int
	for i := 0; i < 2; i++ {
		for j := 0; j < 3; j++ {
			c[i][j] = i + j
		}
	}
	fmt.Println(c)

声明数组类型时,也是在后面写上类型,声明时可以简化i :=0

2.7 基础语法-切片

切片是一种对数组的抽象,可以动态地管理数组中的元素,切片是一个指向底层数组的指针,包含三个属性:指针,长度和容量

s := make([]string, 3)
	s[0] = "a"
	s[1] = "b"
	s[2] = "c"
	fmt.Println(s[2])
	fmt.Println(len(s))

	s = append(s, "e", "f")  //通过内置函数append() 动态增加元素
	fmt.Println(s)

	d := make([]string, len(s))  //可通过函数make()创建,返回一个初始化长度为len的切片
	copy(d, s) //复制
	fmt.Println(d)

	fmt.Println(s[2:5])  //取出第二个到第五个元素之间,不包括第五个元素

	good := []string{"g", "o", "o", "d"}
	fmt.Println(good)

2.8 基础语法-map

Go语言中map为一种内置数据结构,用于存储键值对,键为可比较的数据类型(如字符串、数字),值为任何数据类型

m := make(map[string]int) //利用make() 创建空map,键为字符串,值为整数
	m["one"] = 1  //赋值,one为键,1为值
	m["two"] = 2
	fmt.Println(m)
	fmt.Println(len(m))
	fmt.Println(m["one"])

	delete(m, "one") //利用delete函数删除键值对
	fmt.Println(m)
	m2 := map[string]int{"one": 1, "two": 2} //直接赋值
	var m3 = map[string]int{"one": 1, "two": 2}
	fmt.Println(m2, m3)

2.9 基础语法-range

在 Go 中,range 关键字用于遍历数组、切片、字符串、map 和通道中的元素。对于数组、切片和字符串,它将返回每个元素的索引和值。对于 map,它将返回每个键和值。对于通道,它将返回每个从通道中接收到的值。

nums := []int{2, 3, 4}
	sum := 0
	for i, num := range nums {  //遍历数组
		sum += num
		if num == 2 {
			fmt.Println("index:", i, "num:", num)
		}
	}
	fmt.Println(sum)

	m1 := map[string]string{"a": "A", "b": "B"}  //遍历map
	for k, v := range m1 {
		fmt.Printf(k, v)
	}
	for k := range m1 {  //对于通道,可以在循环中使用range从通道中接收数据,直到该通道关闭
		fmt.Println("key", k)
	}
        for _, k := range m1 {  //遍历中可使用_来忽略该变量
}

2.10 基础语法-函数

Go语言中,函数为一组可重用的代码块,可在程序中多次调用,定义一个函数需要使用关键字func ,函数名称,参数,返回值

func add(a int, b int) int {  //Go语言的类型为后置的,a int
	return a + b
}
func add2(a, b int) int {  //简化,在一行同时声明多个变量
	return a + b
}
//Go中的函数可以有多个返回值,m键值对,v返回结果,ok布尔类型判读是否相同
func exists(m map[string]string, k string) (v string, ok bool) {
	v, ok = m[k]
	return v, ok
}

func main() {
	res := add(1, 2) //调用函数使用函数名称和传递给函数的参数
	fmt.Println(res)

	re := add2(2, 2)
	fmt.Println(re)

	v, ok := exists(map[string]string{"a": "A"}, "a")
	fmt.Println(v, ok)
}

2.11 基础语法-指针

Go 语言中,指针是指向一个变量的地址的变量。指针存储了变量的内存地址,因此可以通过指针来访问和更改变量的值。创建指针需要使用 & 符号,它表示取地址运算符。

func add3(n int) { //函数中的参数默认为传值调用,函数会接收一个变量的副本,而不是变量本身
	n += 2
}  //无效,运行不出来
func add3p(n *int) {  //函数中的参数为一个指针,它指的是main函数中的n变量
	*n += 2
}
func main() {
	n := 5
	add3(n)  //对n变量的更改不会影响main函数的n变量
	fmt.Println(n)
	add3p(&n) //函数中对*n的更改会影响到main函数中的n变量,需加上取地址符&来获取变量的内存地址
	fmt.Println(n)
}

2.12 基础语法-结构体

在 Go语言中,结构体是一种用户定义的数据类型,它可以用来组合不同类型的数据。结构体是一组字段(类似于其他语言中的成员变量或属性)。 定义结构体需要使用关键字 type 和 struct。每个字段都有一个名称和类型。

type user struct {
	name     string
	password string
}

func main() {
	a := user{name: "wang", password: "123"}
	b := user{"wan", "123"}
	c := user{name: "liu"}
	c.password = "132"
	var d user
	d.name = "wa"
	d.password = "111"

	fmt.Println(a, b, c, d)//四种方法进行赋值
	fmt.Println(checkPassword(a, "haha"))
	fmt.Println(checkPassword2(&a, "haha"))
}

func checkPassword(u user, password string) bool {
	return u.password == password
}
func checkPassword2(u *user, password string) bool {
	return u.password == password
}

2.13 基础语法-结构体方法

结构体可定义方法,方法通过结构体实例调用

type user struct {
	name     string
	password string
}
//比较密码
func (u user) checkPassword(password string) bool {
	return u.password == password
}
//修改密码,通过结构体指针来调用方法
func (u *user) resetPassword(password string) {
	u.password = password
}

func main() {
	a := user{name: "wang", password: "111"}
	a.resetPassword("2021")
	fmt.Println(a.checkPassword("2021"))
}

2.14 基础语法-错误处理

在 Go 语言中,错误处理是一个重要的部分。Go 提供了一种简单的方法来处理错误,即将错误作为函数的返回值。

在 Go语言中,错误是一个内置的 error 类型,该类型实现了 error 接口。在错误发生时,函数可以返回一个 error 值

type user struct {
	name     string
	password string
}
//需返回两个值,其中一个为错误信息
func findUser(users []user, name string) (v *user, err error) {
	for _, u := range users {
		if u.name == name {
			return &u, nil  //没有错误则返回原本结果和一个nil
		}
	}
	return nil, errors.New("not found")
}
func main() {
	u, err := findUser([]user{{"wang", "1024"}}, "wang")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(u.name)  //错误不为nil时,运行成功

	if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
		fmt.Println(err)
		return
	} else {
		fmt.Println(u.name)
	}
}

2.15 基础语法-字符串操作

func main() {
	a := "hello"
	b := "你好呀"
	fmt.Println(strings.Contains(a, "ll")) //是否包含有
	fmt.Println(strings.Count(a, "l"))
	fmt.Println(strings.HasPrefix(a, "he"))  //测试字符串是否以he为前缀
	fmt.Println(strings.HasSuffix(a, "llo")) //测试字符串是否以llo为后缀结尾
	fmt.Println(strings.Index(a, "ll"))
	fmt.Println(strings.Join([]string{"he", "llo"}, "-")) //连接其第一个参数的元素以创建单个字符串,分隔符-,。放在字符串中的元素之间
	fmt.Println(strings.Repeat(a, 2))                     //重复
	fmt.Println(strings.Replace(a, "e", "E", -1))         //替换,-1n<0,表示替换次数没有限制
	fmt.Println(strings.Split("a-b-c", "-"))              //分割,去掉分隔符
	fmt.Println(strings.ToLower(a))                       //小写
	fmt.Println(strings.ToUpper(a))                       //大写
	fmt.Println(len(a))                                   //字符串长度
	fmt.Println(len(b))                                   //一个文字占3个长度
}

2.16 基本语法-字符串格式化

type point struct {
	x, y int
}

func main() {
	s := "hello"
	n := 123
	p := point{1, 2}
	fmt.Println(s, n)
	fmt.Println(p)

	fmt.Printf("s=%v\n", s) //printf 字符串,数据格式化输出
	fmt.Printf("n=%v\n", n)
	fmt.Printf("p=%v\n", p)
	fmt.Printf("p=%+v\n", p)//%+v添加字段名(结构体)
	fmt.Printf("p=%#v\n", p)//%#v相应值的go语法表示

	f := 3.1415926
	fmt.Println(f)
	fmt.Printf("%.2f\n", f)
}

2.17 基础语法-JSON处理

json是一种数据交换格式,常用于前后端数据传输,变量首字母大写才可以转成json

type userInfo struct {
	Name  string
	Age   int `json:"age`
	Hobby []string
}

func main() {
	a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "typeScript"}}
	//若编码成功,err赋于零值nil,变量buf为一个进行json格式化之后的[]byte类型
	buf, err := json.Marshal(a) //将数据编码成json字符串
	//指针,切片,映射,通道,函数,接口零值为nil
	if err != nil {
		panic(err) //终止运行
	}
	fmt.Println(buf)
	fmt.Println(string(buf))

	buf, err = json.MarshalIndent(a, "", "\t") //用缩进对输出进行格式化,1想要编成的json结构体,2前缀通常设置为""即可,3缩进通常设置为\t即可
	if err != nil {
		panic(err)
	}
	fmt.Println(string(buf))

	var b userInfo
	err = json.Unmarshal(buf, &b) //将json字符串解码到相应数据结构
	if err != nil {
		panic(err)
	}
	fmt.Printf("%#v\n", b)
}

2.18 基础语法-时间处理

Go语言中使用time包来处理时间

func main() {
	now := time.Now() //快速获取时间
	fmt.Println(now)
//自己构造时间
	t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
	t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC)
	fmt.Println(t)
//输出年份,月份,天数,小时,分钟
	fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute())
//格式化时间,类似于java语言中的yyyy-MM-dd
	fmt.Println(t.Format("2020-1-1 15:12:11"))
	diff := t2.Sub(t)
	fmt.Println(diff.Minutes(), diff.Seconds())
	t3, err := time.Parse("2020-1-1 15:12:11", "2022-1-1 21:11:11")
	if err != nil {
		panic(err)
	}
	fmt.Println(t3 == t)
	fmt.Println(now.Unix())
}

2.19基础语法-数字解析

strconv包是 Go 语言标准库中用于字符串与数字之间转换的包。它提供了许多函数来实现字符串和整数、浮点数、布尔值之间的转换

func main() {
	f, _ := strconv.ParseFloat("3.142", 64)
	fmt.Println(f)

	n, _ := strconv.ParseInt("111", 10, 64)
	fmt.Println(n)

	n, _ = strconv.ParseInt("0x1000", 0, 64)
	fmt.Println(n)

	n2, _ := strconv.Atoi("123")//字符串转int int转字符串:itoa()
	fmt.Println(n2)

	n2, err := strconv.Atoi("AAA")
	fmt.Println(n2, err)
}

2.20 基础语法-进程信息

func main() {
	fmt.Println(os.Args)
	fmt.Println(os.Getenv("PATH"))
	fmt.Println(os.Setenv("AA", "BB"))

	buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
	if err != nil {
		panic(err)
	}
	fmt.Println(string(buf))
        }

总结

经过第一课的认识,了解了Go语言的基本语法,认识到自己的不足,与之前所学的其他语言不太一样,还是不太理解。不太熟练,实战案例有一些难懂。放松心态去进行之后的课程学习,希望可以熟练掌握Go语言