GO语言基础|青训营笔记
这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
一、GO语言的特点
1.高性能、高并发
拥有和C++、Java媲美的性能,内含对高并发的支持,只需要使用标准库或者基于标准库开发的第三方库,就可以开发高并发应用程序。
2.语法简单、学习曲线平缓
下面通过实现一个http服务器来简单了解下GO
package main
import(
"net/http"
)
func main(){
http.Handle("/",http.FileServer(http.Dir("."))) //把“/”这个路由指向静态文件
http.ListenAndServe(":8080",nil)//增添8080端口并启动服务器
}
3.拥有丰富的标准库
很多情况下不需要借用第三方库,就可以完成基础功能的开发,大大降低学习和使用成本,且有很大的稳定性。
4.完善的工具链
代码格式化、错误检查、帮助文档、包管理、代码补充提示、单元测试框架等。
5.静态链接
所有编译结构默认都是静态链接的,只需要拷贝编译后的可执行文件就可部署运行,部署非常方便快捷。
6.快速编译
拥有静态语言里几乎最快的编译速度。
7.跨平台
可以在各种操作系统下运行,也可用来开发IOS,Android软件,含有交叉编译功能,无需配置交叉编译环境。
8.垃圾回收
拥有垃圾回收功能,无需考虑内存的分配释放,可专注于业务逻辑。
二、GO语言基础语法
1.梦开始的地方------------Hello,World!
package main //表示文件属于main包,也就是程序的入口
import (
"fmt" //fmt包主要用来输入输出字符串格式化字符串
)
func main() {
fmt.Println("Hello,World!") //调用fmt包内的Println打印hello,world
}
程序执行结果如下
2.变量与常量
- 变量类型:整型int、无符号整型uint、浮点型float、布尔型boolean、复数complex、字符串string,GO中没有字符类型(char),而是使用byte和rune来代表字符,[]byte也可表示字符串。
- 变量的声明方式
var e float64 //仅声明变量未赋值
var a = "hello" //var+变量名=变量的值
var b,c int = 1,2 //var+变量名+变量类型=变量的值
f := float32(e) //当左边的变量之前没有定义过时,可以使用:=
- 常量的赋值方式
const a = 100
const b = "abcd" //var改为const即可,可根据使用的上下文自动确定类型
需要注意的是,go语言中,变量定义之后,必须要使用,也可使用匿名变量,用下划线表示。
3.if else语句
if 9%2 == 0{ //判断条件不需要用括号括起来
fmt.Println("9 is even")
}else {
fmt.Println("9 is odd")
}
if 条件{
语句
}else{
语句
}else{
语句
}
4.for循环
- 写一个死循环
for {
fmt,println("hello")
}
- 普通格式的for循环
for j := 1 ; j < 10 ; j++ {
fmt.Println(j)
} //参考C语言的for循环
- 另一种条件循环
i ;= 1
for i < 5{
fmt.Println(i)
i = i + 1
}
- 使用break直接结束循环,使用continue后面的语句不再执行跳到下一次循环
5.switch分支结构
与C++、Java中的switch也是十分的相似
switch a {
case 1:
语句 //值得注意的是,与C++不同,这里语句结束并不需要加上break,程序不会自动跑完剩下分支
case 2:
语句
case 3:
语句
default:
语句
}
go语言的switch功能更加强大,可以使用任意的数据类型作为条件,也可以在switch后面不加判断条件,而是在case后面去写条件分支。
switch {
case i < 1:
语句
default:
语句
}
6.数组
- 数组的声明方式
var a [5]int //意为定义了一个长度为5的整型数组a
b := [5]int{1,2,3,4,5} //定义的同时为数组赋值
a[3] = 1 //为数组的某一位赋值
由于数组长度固定,在GO中我们更多地使用切片而不是数组
7.切片
切片是一个可变长度的数组,拥有更多丰富的操作,以下是切片创建的方法以及一些操作
s := make([]int, 3) //创建一个切片s,长度为3
s[0] = 1
s[1] = 2
s[2] = 3
fmt.Println("get:",s[2]) //输出3
fmt.Println("len:",len(s)) //输出3,为s的长度
s = append(s,"4") //使用append追加元素
s = append(s,"5","6","7")
fmt.Println(s) //输出结果为[1,2,3,4,5,6,7]
进行切片操作
fmt.Println(s[2:5]) //[3,4,5],左闭右开
fmt.Println(s[:5]) //[1,2,3,4,5]
fmt.Println(s[3:]) //[4,5,6,7]
8.map
定义一个map,类似于python中的字典
m := make(map[string]int)//string对应键,int对应值,后面接{“one”:1,“two”:2}可直接传入键值对
m["one"] = 1
m["two"] = 2
fmt.Println(m["unknow"]) //0
delete(m,"one") //删除键值对
r,ok :=m["unknow"] //后面接一个ok来看值是否存在
fmt.Println(r,ok) //0 false
9.range
可以使用range快速遍历map,返回索引和值,如果不需要索引可用下划线忽略
for k,v :=range m{
fmt.Println(k,v) //"one" 1;"two" 2(不分前后顺序)
}
for v :=range m{
fmt.Println("key",v) //"key" 1;"key" 2(不分前后顺序)
}
10.函数
与C++十分相似,比较特殊的点在于变量类型是后置的
func add(a int,b int) int{
return a + b
}
Golang的函数原生支持返回多个值,在实际业务逻辑中,函数不仅会返回值,还会返回一个布尔类型的变量,以表示错误信息
func exists(m map[string]string, k string)(v string, ok bool){
v, ok = m[k]
return v, ok
} //后面括号括起来的表示返回值
11.指针
Golang也支持指针,但是相比C、C++,它支持的操作十分有限,只要作用是修改函数传入的参数。
func add(n *int){
*n += 2
}
func main(){
n := 5
add(&n)
mt.Println(n) //结果为7,不使用指针的话结果仍然为5
}
12.结构体
type user struct{
name string
password string
} //定义一个结构体user
func main(){
a := user{name:"Liu",password:"123"} //初始化一个结构体变量
b := user{"Wang","342"}
C := user{name:"Li"} //对于为初始化的字段,就为空值
c.password = "564" //也可通过这个方法访问其中字段
var d user //直接定义一个结构体成员
}
在函数中,通过使用结构体的指针,来改变结构体的内容
func changePassword(u *user){
u.password = "666"
}
13.结构体方法
定义方法的语法格式:* func (接收者变量 接收者类型) 方法名(参数列表) (返回值列表){ //方法体 }
type user struct{
name string
password string
}
func (u user) checkPassword(password string) bool{ //将结构体的传入参数放到了函数名前面的的括号
return u.password == password
}
func (u *user) resetPassword(password string) string{ //带指针的结构体方法可以对结构体进行修改
u.password = password
}
14.错误处理
GO语言使用一个单独的返回值处理错误信息,可以清晰地知道哪个函数返回了错误,能够用简单的if-else去处理错误。
func finfUser(users []user,name string)(v *user,err error){ //在返回参数的位置,加入一个error
for _, u := range users{
if u.name == name{
return &u,nil
}
}
return nil,errors.New("Not Found") //通过errors.New返回错误信息
}
15.字符串操作
a := "hello"
fmt.Println(strings.Contains(a,"ll")) //true
fmt.Println(strings.Count(a,"l")) //2
fmt.Println(strings.HasPrefix(a,"he")) //true
fmt.Println(strings.HasSuffix(a,"llo")) //true
fmt.Println(strings.Index(a,"ll")) //2
fmt.Println(strings.Join([string{"he","llo"},"-"])) //he-llo
fmt.Println(strings.Repeat(a,2)) //hellohello
fmt.Println(strings.Replace(a,"e","E",-1)) //hEllo,-1表示替换全部字符串,为n(n不等于-1)时替换n个字符串
fmt.Println(strings.Split("a-b-c","-")) //[a,b,c]
fmt.Println(strings.ToLower(a)) //hello
fmt.Println(strings.ToUpper(a)) //HELLO
fmt.Println(len(a)) //5
fmt.Println(len("你好")) //6
16.字符串格式化
type point struct{
x, y int
}
p := point{1, 2}
fmt.Println(s, n) //表示打印s和n
fmt.Printf("s=%v\n", s) //%v表示打印的变量s
fmt.Printf("p=%+v\n", p) //以键值对的形式进行打印,p={x;1 y:2}
fmt.Printf("p=%#v\n", p) //先输出结构体名字值,再输出结构体(字段类型+字段的值),p=main.point{x:1,y:2}
fmt.Printf("%.2f\n", f) //控制浮点数精度
17.Json处理
结构体中,字段名的第一个字母均为大写时,我们便可以使用json.Marshal去对其进行序列化,序列化的结果是一个byte数组,打印时需要将其转换为string类型,否则打印结果将是一些二进制数。
type yserInfo struct {
Name string
Age int json:"age" //这样一来序列化后打印出的是age而不是Age
Hobby []string
}
a := userInfo{Name:"Liu",Age:"19",Hobby: []string{"Golang","Java"}} //userInfo为我们定义的结构体
buf, err := json.Marshal(a) //序列化
if err != nil {
panic(err) //panic抛出异常
}
fmt.println(string(buf))
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
// v: 想要编码成json的结构体|map
// prefix: 前缀,通常就设置为""即可。
// indent:缩进,通常设置为制表符\t即可
err = json.Unmarshal(buf,&b) //反序列化
18.时间处理
now := time.Now() //获取当前时间
t := time.Date(2022,5,23,2,30,45,0,time,UTC) //年,月,日,时,分,秒
fmt.Println(t.Year(),t.Month(),t.Day(),t.Hour(),t.Minute)
diff = t2.sub(t) //表示两个时间段相减
t.format("2006-01-02 15:04:05") //将时间格式化成字符串的样子,该字符串为官方指定
t3,err = time.Parse("2006-01-02 15:04:05","2002-3-13 04:34:12") //同样使用该字符串,将一个字符串转换为时间
now.Unix() //获取一个时间戳
19.字符串与数字之间的转换
相关的函数包含在strconv包之中
f,_ := strconv.ParseFloat("2.33",64) //转换为64精度的float
f,_ := strconv.ParseInt("2123",10,64) //转换为整数--字符串,进制,位数
n,_ := strconv.Atoi("123") //快速将字符串转为数字
20.进程信息
获取进程相关的一些信息,用到的包有os,os/exec
fmt.Println(os.Args) //获取进程在执行的时候一些命令行参数
os.Getenv("PATH") //获取环境变量
os.Setenv("AA","BB") //设置环境变量
buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput() //快速启动子进程
三、学习体会
GO语言,相对于C++和Java简化了不少语法,同时也引入了python中的切片操作,可以说是一门集几家之长的编程语言。 学习的过程中,发现GO语言的变量定义与其他几门语言有一个很显著的区别,那就是GO语言规定了,变量只要被定义了就一定要使用,否则就会报错。不过如果我们也可以使用匿名变量代替之,也就是说以“_”作为变量名。很多时候GO语言中调用的函数返回值并不止一个,还有一个包含错误信息值,当我们不需要某个返回值时,便可以使用匿名变量。