一.Go语言上手-基础语言
1.简介
1.1 什么是Go 语言
- 高性能、高并发(与c/c++/java一样的性能)
- 语法简单、学习曲线平缓
- 丰富的标准库
- 完善的工具链
- 静态链接(与java不同,不需要通过中间代码表示和支持代码运行,直接将代码静态链接并编译 )
- 快速编译
- 跨平台
- 垃圾回收
2.入门
2.1 开发环境
1.安装 Golang
2.配置集成开发环境
vscode:https://code.visualstudio.com
goland:https://www.jetbrains.com/go/
Vscode自由性更高,goland更适用(学生可以使用教育优惠,免费使用Jetbrains 申请一份免费的教育许可证或申请 GitHub Education 学生包)
注意:go语言使用goland需要配置环境变量(尤其是GOPATH),以mac为例:
在终端中
在命令行中运行 go env 后,查看 Go 开发包的环境变量配置信息,这些配置信息里可以查看到当前的 GOPATH路径设置情况。
GOPATH是Go 语言中使用的一个环境变量,它使用绝对路径提供项目的工作目录。
GOPATH 环境变量指定了 你的工作空间位置。它或许是你在开发Go代码时,唯一需要设置的环境变量。
GOPATH 适合处理大量 Go 语言源码、多个包组合而成的复杂工程。
配置GOPATH
vi ~/.bash_profile
export GOPATH:/Users/xx/go
source ~/.bash_profile
注意:千万不要把GOPATH设置成go的安装路径,可以自己在用户目录下创建一个目录,例如:go。否则当使用 go env检查当前环境是否生效时,会提示警告。
warning: GOPATH set to GOROOT (/usr/local/go) has no effect
2.2基础语法
1.Hello world
package main
import (
"fmt"
)
func main() {
fmt.Println("hello world")
}
fmt.Println为输出语句,Println 中的 P 是大写的,类似于System.out.println(java)。
在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,它们都将被go语言编译器完成
2.变量
Go 语言中变量的声明必须使用空格隔开,在关键字和表达式之间要使用空格。
- 变量:使用 var 关键字声明变量,包括类型,如 var i int。
var a int =1(Go语言变量类型后置)
var a,b int =1,2(同行声明多个变量)
var a=true(变量类型自动判断)
var a float64(未初始化的变量,必须指定变量类型,初始值自动初始化)
a := 4 // 相当与var a = 4(简写)
- 常量:使用 const 关键字声明常量,如 const pi = 3.14159。
go语言里面的常量,它没有确定的类型,会根据使用的上下文来自动确定类型。
- 数据类型:包括 int、float、bool、string、struct、array、map、channel 等。
float32(指32位浮点型数)
3.if else
- if 语句:使用 if 和 else 关键字,如
if i > 0 {
fmt.Println(i)
}
if 7%2 == 0 {
fmt.Println("7 is even")
} else {
fmt.Println("7 is odd")
}
if 8%4 == 0 {
fmt.Println("8 is divisible by 4")
}
if num := 9; num < 0 {
fmt.Println(num, "is negative")
} else if num < 10 {
fmt.Println(num, "has 1 digit")
} else {
fmt.Println(num, "has multiple digits")
}
if后面的括号在go语言中不需要使用,但是后面的括号{}是必需的(单句也是一样的)
4.循环
- for 循环:使用 for 关键字,如
for i := 0; i < 10; i++ {
fmt.Println(i)
}
Go语言只有for一种
类似while语句:
i := 1
for i <= 2 {
fmt.Println(i)
i++
}
5.switch
- switch 语句:使用 switch 关键字,如
i := 0
switch i {
case 0:
fmt.Println("zero")
case 1:
fmt.Println("one")
}
省略 switch 后的变量:
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("It's before noon")
default:
fmt.Println("It's after noon")
}
switch语句中每个case都隐含着break
不含break,需要使用fallthrough(相当于break的反义词),只能用在case语句末尾
6.数组
- 声明数组:使用 var 关键字,如
var a [5]int
a[4] = 5
简化:
a := [5]int{1, 2, 3, 4, 5}
多维数组:
var a [1][2]int
7.切片
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。(类似于java的ArrayList)
- 声明切片:使用 var 关键字和 := 操作符,如
var slice []int(声明一个未指定大小的数组来定义切片) 和 slice := make([]int, 5) (使用 make() 函数来创建切片)。
切片与数组不同,切片不需要在 [] 内指定一个长度,而数组是需要的。
切片的长度与容量。长度表示:实际切片的长度,容量表示:一个上限,长度到达上限,切片会进行扩容
可以直接定义切片的长度与容量
slice := make([]int, 5,10)
切片的赋值与数组一样:
s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("get:", s[2]) //c
fmt.Println("len:", len(s)) //3
可以使用数组相同的方法获取切片值,但是在越界下,有着不同的反馈
数组:
fmt.Println(s[4]) // error: invalid argument: index 4 out of bounds [0:4]
切片:
fmt.Println(s[4]) // panic: runtime error: index out of range [4] with length 4
可以使用append方法为数组添加新的元素,(注意:append的结果赋值给原数组):
s = append(s, "d")
s = append(s, "e", "f")
fmt.Println(s) //[a b c d e f]
可以使用 copy 方法将一个切片内的元素复制到另一个切片中:
c := make([]string, len(s))
copy(c, s)
在数组和切片中截取元素:
第2到第4的值:
fmt.Println(s[2:5])//[c d e]
第 0 到第 4 的值:
fmt.Println(s[:5]) // [a b c d e]
第 2 到第 5 的值:
fmt.Println(s[2:]) // [c d e f]
第 0 到第 5的值:
fmt.Println(s[:]) // [a b c d e f]
8.map(集合)
Map 是一种无序的键值对的集合(映射)
Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值
Map会自动扩容。如果不指定参数 ,Go 语言会根据实际情况选择一个合适的值。
-声明map并赋值,与数组和切片不同,将[]换为key如
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
声明了一个键(key)为 string 类型,值(value)为 int 类型的 Map。
指定参数:
m := make(map[string]int, 10)
初始化Map内的值:
m := map[string]int{
"one": 1,
"two": 2
}
使用 len 方法获得一个 Map 内包含键值对的长度:
fmt.Println(len(m)) // 2
获取一个值:
fmt.Println(m["one"]) // 1
访问不存在的key,返回初始值(此方法无法判断Map是否存在):
fmt.Println(m["unknown"]) // 0
判断:
v1, ok := m["unknown"]
fmt.Println(v1, ok) // 0 false
使用 delete 函数从一个 Map 中移除指定的键:
delete(m, "one")
9.range
range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对
for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环,如:
nums := []int{2, 3, 4}
sum := 0
for i, num := range nums {
sum += num
if num == 2 {
fmt.Println("index:", i, "num:", num) //index:0 num:2
}
}
fmt.Println(sum)//9
m := map[string]string{"a": "A", "b": "B"}
for k, v := range m {
fmt.Println(k, v) //a A;b B
}
for k := range m {
fmt.Println("key", k) //key a;key b
}
10.函数
-声明带返回值的函数:
func add(a int, b int) int {
return a + b
}
声明了add()函数,类型为int,形参为a,b
11.指针
Go的指针与c/c++不同,主要的用途就是传入参数修改,不能进行地址运算,如:
func add2(n int) {
n += 2
}
func add2ptr(n *int) {
*n += 2
}
func main() {
n := 5
add2(n) // not working
fmt.Println(n) // 5
add2ptr(&n)
fmt.Println(n) // 7
}
12.结构体
- 声明结构体:使用 type 关键字和 struct 语句,如
type user struct {
name string
password string
}
初始化结构体:
a := user{name: "wang", password: "1024"}
b := user{"wang", "1024"}
c := user{name: "wang"}
c.password = "1024"
var d user
d.name = "wang"
d.password = "1024"
fmt.Println(a, b, c, d) //{wang 1024} {wang 1024} {wang 1024} {wang 1024}
访问结构体成员:
fmt.Println(a.name)//wang
13.结构体方法
- 方法:使用 func 关键字和 struct 结构体,如
检查用户密码是否匹配的方法:
func (u user) checkPassword(password string) bool {
return u.password == password
}
重置用户密码为指定值的方法:
func (u *user) resetPassword(password string) {
u.password = password
}
需要使用指针修改原结构体
调用:
a.resetPassword("2048")
fmt.Println(a.checkPassword("2048")) // true
14.错误处理
Go 语言通过内置的错误接口提供了非常简单的错误处理机制。
需要需要导入 errors 包:
import (
"errors"
)
声明函数:
func findUser(users []user, name string) (v *user, err error){
for _,u := range users {
if u.name == name {
return &u, 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) // wang
if u, err := findUser([]user{{"wang", 1024}}, "li"); err != nil {
fmt.Println(err) // not found
return
} else {
fmt.Println(u.name)
}
}
通过判断 err 是否为 nil 来得知错误是否发生
15.字符串操作
需要需要导入 errors 包:
import (
"strings"
)
go语言里面的字符符操作。在标准库strings 包里面有很多常用的字符串工具函数,比如 contains 判断一个字符串里面是否有包含另一个字符串,count 字符串计数,index 查找果个字符串的位置。join 连接多个字符串repeat 重复多个字符串 replace 替换字符串
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))//hellohelllo
fmt.Println(strings.Replace(a, "e", "E", -1))//hEllo
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
b := "你好"
fmt.Println(len(b))//6
16.字符串格式化
Go语言中printf类似于c语言,不同的是可以用%v打印任意类型的变量,用%+v打印详细结果,%#v打印更详细
type point struct {
x, y int
}
func main() {
p := point{1, 2}
fmt.Println(p) // {1 2}
fmt.Printf("p=%v\n", p) //p={1,2}
fmt.Printf("p=%+v\n", p) // p={x:1 y:2}
fmt.Printf("p=%#v\n", p) //p=main.point{x:1, y:2}
}
17.JSON处理
- 将JSON转换为字符串:json.Marshal()
- 将字符串转换为JSON:json.Unmarshal()
- JSON字符串转字典:json.UnmarshalDict()
- JSON字符串转集合:json.UnmarshalList()
- JSON格式化输出json.Marshalindent
Go语言的JSON操作,已有结构体的只需要字段首字母大写(公开字段),就可以json.Marshal()系列化
导encoding/json包
import (
"encoding/json"
)
JSON格式化输出:
buf, err = json.MarshalIndent(a, "", "It")
{
It"Name": "wang",
It"Age": 18,
It"Hobby": [
ItIt"Golang",
ItIt"TypeScript"
It]
}
18.时间处理
- 获取当前时间:time.Now()
- 获取时间戳:time.Now().Unix(), time.Now().UnixNano()
- 格式化时间:time.Format()
- 时间间隔:time.Duration
- 时间处理函数:time.After(), time.Now().After()
6.构造时间:time.date(2023,7,26,12,00,time.UTC)
导time包
import (
"time"
)
19.数字解析
- int和float转换:float64(), int()
- 浮点数转换为字符串:strconv.FormatFloat()
- 字符串转换为整数:strconv.Atoi()
- 字符串转换为浮点数:strconv.ParseFloat()
- 格式化数字:strconv.Itoa()
- 字符串格式化数字:fmt.Sprintf()
输入不合法,返回error
导strconv包
import (
"strconv"
)
n, _ := strconv.ParseInt("0x1000", 0, 64)
fmt.Println(n) // 4096
n2, err := strconv. Atoi( "AAA" )
fmt.Println(n2, err)0// strconv.Atoi: parsing "AAA": invalid syntax
20.进程信息
导包
import (
"fmt"
"os"
"os/exec"
)
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))