这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
一、什么是Go语言:
1、高性能、高并发
2、语法简单、学习曲线平缓
3、丰富的标准库
4、完善的工具链
5、静态链接
6、快速编译
7、跨平台
8、垃圾回收
二、创建第一个Go项目:
第一步:go mod init xxx(任意名字)
第二步:创建一个xxx.go项目
第三步:在控制台输入 go run .\xxx.go 或者直接运行
例如我们输出一个helloword,首先通过上面3步创建一个go项目,然后代码如下
package main
import "fmt"
func main() {
fmt.Println("helloword")
}
三、Go基础语法:
(1)go语言通过var来声明变量
1、可以直接通过var a=xxx 来声明变量,可以自动解析变量的类型
2、也可以通过var b int来确定变量类型
3、常量的声明:只需在前面添加const关键字即可,具体代码如下
package main
import (
"fmt"
"math"
)
func main() {
var a = "initial"
var b, c int = 1, 2
var d = true
var e float64
f := float32(e)
g := a + "foo"
fmt.Println(a, b, c, d, e, f)
fmt.Println(g)
const s string = "constant"
const h = 500000000
const i = 3e20 / h
fmt.Println(s, h, i, math.Sin(h), math.Sin(i))
}
(2)if-else的使用
相比较与java的if-else没有太多的变化,只是判断体不需要()
package main
import (
"fmt"
)
func main() {
if 7%2 == 0 {
fmt.Println("7 is even")
} else {
fmt.Println("7 is 0dd")
}
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 multinle")
}
}
(3)for的使用
for的使用跟java比较像,只是循环体没有在(),其他的理解跟java一样理解
package main
import (
"fmt"
)
func main() {
i := 1
for {
fmt.Println("loop")
break
}
for j := 7; j < 9; j++ {
fmt.Println(j)
}
for n := 0; n < 5; n++ {
if n%2 == 0 {
continue
}
fmt.Println(n)
}
for i <= 3 {
fmt.Println(i)
i = i + 1
}
}
(4)switch的使用
switch默认是不需要break跳出循环的,注意这点即可
package main
import (
"fmt"
"time"
)
func main() {
a := 2
//默认是不需要break跳出循环的
switch a {
case 1:
fmt.Println(1)
case 2:
fmt.Println(2)
case 3:
fmt.Println(3)
case 4, 5:
fmt.Println(45)
default:
fmt.Println("other")
}
}
(5)数组与切片的使用
数组是长度一定的,而切片的长度是可以扩容的,所以我们在不确定数组的长度时最好用切片,而对于知道数组的最大长度,用数组也是可以的
数组的定义代码所示
func main() {
var a [5]int
a[4] = 100
fmt.Println(a[4], len(a))
b := [5]int{1, 2, 3, 4, 5}
fmt.Println(b)
var twoD [2][3]int
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("2d", twoD)
}
切片:切片是通过make关键字来创建的,详细请看代码注释
func main() {
s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("get", s[2])
fmt.Println("len", len(s)) //获取s的长度
s = append(s, "d") //添加一个
s = append(s, "e", "f") //添加两个
fmt.Println(s)
c := make([]string, len(s))
copy(c, s) //将s中的值copy到c中
fmt.Println(c)
fmt.Println(s[2:5]) //输出下标为2到下标为4的值,即左闭右开
fmt.Println(s[:5]) //输出5个
fmt.Println(s[2:]) //从下标为2的开始输出
good := []string{"g", "o", "o", "d"}
fmt.Println(good)
}
(6)map的使用
map是存储键值的数据,它可以通过声明来确定存储k,v的类型,该结构常用于1对1数据时,通过键值存储来达到数据的绑定
func main() {
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
fmt.Println(m)
fmt.Println(len(m))
fmt.Println(m["one"])
fmt.Println(m["unknow"]) //0
r, ok := m["unknow"]//检查是否存在这个key
fmt.Println(r, ok) //0 false
delete(m, "one")
m2 := map[string]int{"one": 1, "two": 2}
var m3 = map[string]int{"one": 1, "two": 2}
fmt.Println(m2, m3)
}
(7)遍历-range
对存储数据的结构进行遍历的函数,具体看代码即可
func main() {
nums := []int{2, 3, 4}
sum := 0
for i, num := range nums {
sum += num
if num == 2 {
fmt.Println("index:", i, "num", num) //0,2
}
}
fmt.Println(sum) //9
m := map[string]string{"a": "A", "b": "B"}
//键值遍历
for k, v := range m {
fmt.Println(k, v) //b 8;a A
}
//键遍历
for k := range m {
fmt.Println("key", k) //key a;key b
}
}
(8)函数 函数是我们最常用的,与java的方法相似,通过声明函数的参数类型、返回值等来构建函数,函数的作用就是使代码简洁,让学习的人一看就明白,也可以减少代码的重复
// 参数 类型 返回值
func add(a int, b int) int {
return a + b
}
func add2(a, b int) int {
return a + b
}
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) //3
v, ok := exists(map[string]string{"a": "A"}, "a")
fmt.Print(v, ok) //A True
}
(8)指针
传入的参数分为两种:1、值传递 2、地址传递,而指针则是地址传递,它是传入该参数的地址,修改时参数传入的参数也会被修改,而值传递不会修改传入的参数的值
// 参数 类型 返回值
func add2(a int) {
a += 2
}
func add2ptr(a *int) {
*a += 2
}
func main() {
n := 5
add2(n)
fmt.Println(n)//5
add2ptr(&n)
fmt.Println(n)//7
}
(8)结构体和结构体方法
结构体就是声明一个实体类一样的思想,将各种参数的类型以及id声明在结构体内,便于更好的封装。
结构体方法也区别指针和值传递,跟函数类似
type user struct {
name string
password string
}
func main() {
a := user{name: "wang", password: "1024"}
a.checkPassword2("2048")
fmt.Println(a.checkPassword("2048"))
}
func (u user) checkPassword(password string) bool {
return u.password == password
}
func (u *user) checkPassword2(password string) {
u.password = password
}
(9)错误处理
可以自己创建一个函数来处理错误,使错误更具有识别性
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")
}v
(10)字符串格式化,时间格式
这个没有太多思想,观看代码即可
package main
import (
"fmt"
)
type point struct {
x, y int
}
func main() {
s := "hello"
n := 123
p := point{1, 2}
fmt.Println(s, n) //hello 123
fmt.Println(p) //{1 2}
fmt.Printf("s=%v\n", s) //s=hello
fmt.Printf("s=%v\n", n) //s=123
fmt.Printf("s=%v\n", p) //s={1 2}
fmt.Printf("s=%+v\n", p) //s={x:1 y:2}
fmt.Printf("s=%#v\n", p) //s=main.point{x:1, y:2}
f := 3.141592653
fmt.Println(f) //3.141592653
fmt.Printf("%.2f\n", f) //3.14
}
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println(now) //2023-01-15 17:23:58.5944814 +0800 CST m=+0.005750801
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) //2022-03-27 01:25:36 +0000 UTC
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) //2022 March 27 1 25
//日期格式化
fmt.Println(t.Format("2006-01-02 15:04:05")) //2022-03-27 01:25:36
//两个时间相减
diff := t2.Sub(t)
fmt.Println(diff) //1h5m0s
fmt.Println(diff.Minutes(), diff.Seconds()) //65 3900
t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")
if err != nil {
panic(err)
}
fmt.Println(t3 == t) //true
//获取时间戳
fmt.Println(now.Unix()) //1673774638
}
(11)数字解析
数字解析可以有利于我们对string类型和int以及其他的数据之间的转换,可以设置精度以及进制,方便于对类型的转换
package main
import (
"fmt"
"strconv"
)
func main() {
f, _ := strconv.ParseFloat("1.234", 64)
fmt.Println(f) //1.234
//字符串 10:进制 返回64位的精度
n, _ := strconv.ParseInt("111", 10, 64)
fmt.Println(n) //111
n, _ = strconv.ParseInt("0x1000", 0, 64)
fmt.Println(n) //4096
n2, _ := strconv.Atoi("123")
fmt.Println(n2) //123
n2, err := strconv.Atoi("AAA")
fmt.Println(n2, err) //0 strconv.Atoi: parsing "AAA": invalid syntax
}