这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
一 go语言语法基础
1.1 声明
- go的变量声明用var,常量用const。
- go可以一次性声明多个变量
- go声明的变量,如果没有赋值,则都是默认初始值
- 变量有string,byte,int,float32/64,bool等类型
- 在用var声明变量时,编译器会根据值自动推导,也可以指定类型。
// 定义
var a = 1 // 单个变量定义
var b, c // 多个变量定义
var d int = 10 // 定义时声明类型
var e string // 只声明不赋值,必须指定类型
const a = 10
const a int = 10
1.2 循环
go语言中只有一种循环——for循环。for循环一共有3种使用方法:
- 当while使用;
- 标准的c/c++/java模式;
- 死循环
func main() {
i := 1
// while循环
for i <= 3 {
fmt.Println(i)
i = i + 1
}
// 经典循环
for j := 7; j <= 8; j++ {
fmt.Println(j)
}
// 死循环
for {
fmt.Println("loop")
break
}
}
1.3 if-else
go的if-else与c/c++/java基本一样,就是条件不需要小括号括起来,而且条件后面的内容必须用大括号括起来。
除此以外,go的if还能像for一样初始化变量。这个变量的生命周期在if - else的块周期一样
func main() {
// 只有if
if 7%2 == 0 {
fmt.Println("7 is even")
}
// 初始化
if num := 19; num < 0 {
fmt.Println(num, "is negative")
} else if num < 10 {
fmt.Println(num, "is less than 10")
} else {
fmt.Println(num, "has multiple digits")
}
}
1.4 switch
go的switch相较于c++的会丰富很多。首先,它只会执行case里面的代码,不需要每个case结束后就break。
其次switch后面跟的可以是任意值,只要满足case的条件就行。
然后case还可以当作if一样,在前面添加条件
func main() {
i := 2
switch i {
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
case 3:
fmt.Println("three")
}
// 选择多个
switch time.Now().Weekday() {
case time.Saturday, time.Sunday:
fmt.Println("it is the weekend")
default:
fmt.Println("it is a weekday")
}
// 非==判断
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("it is before noon")
default:
fmt.Println("it is after noon")
}
}
1.5 数据结构
go常用的数据结构有:数组,切片,字典
数组很简单,定义如下,用法跟c++一样的。
var a [4]int
var b [4]int{1, 2, 3, 4}
切片可以看作是变长数组
用make函数定义切片,用append给切片添加元素
slice的切片操作:左闭右开
func main() {
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
s = append(s, "d")
s = append(s, "e", "f")
fmt.Println(s[2:5]) // [c d e]
fmt.Println(s[:5]) // [a b c d e]
fmt.Println(s[2:]) // [c d e f]
}
字典,就是c++中的map和Java中的HashMap,同样用make创建,也可以像切片那样用{key: value}的形式创建。
m := make(map[string]int)
m2 := map[string]int{"one": 1, "two": 2}
在利用key获取value的时候,map返回两个值,第一个是实际的值,第二个是一个bool类型的量,表示是否存在该key。我们可以利用这个bool判断map中是否存在该key
1.6 函数
go的函数命名是 func Name(para Type) (返回值) {函数体}。go的函数相比于c++有以下特点
- 可以返回多个值
- 可以为返回值命名
- 相同类型的参数可以简写
func add(a int, b int) int {
return a + b
}
func add2(a, b int) (c int) {
c = a + b
return
}
1.7 结构体
go中的结构体有点像其他的语言里面的类。结构体里面定义数据类型。
type user struct {
name string
password string
}
结构体的方法叫接收器,类似于类的成员函数。在func的后面加一个结构体的声明表明该方法是这个结构体的接收器。接收器的结构体对象一般有两种:值和指针。如果是值,就无法改变结构体的变量值。
func (u user) checkPassword(password string) bool {
return u.password == password
}
1.8 字符串操作
字符串处理的包主要有两个:strings和strconv
strings包主要的一些功能
strings.Contains(a, "ll")) // 包含字符串
strings.Count(a, "l")) // 统计字符串出现次数
strings.HasPrefix(a, "he")) // 是否是前缀
strings.HasSuffix(a, "llo")) // 是否是后最
strings.Index(a, "ll")) // 索引
strings.Join([]string{"he", "llo"}, "-")) // 连接
strings.Repeat(a, 2)) // 重复
strings.Replace(a, "e", "E", -1)) // 替换
strings.Split("a-b-c", "-")) // 切分
strings.ToLower(a)) // 转大写
strings.ToUpper(a)) // 转小写
strconv主要是字符串转换
1.9 json处理
将struct转化为json字符串。从json字符串生成结构体
json.Marshal(struct) ([]byte, error) 将结构体解析成json字符串
json.Unmarshal([]byte, struct) 从json字符串中解析struct,注意这里的结构体要传地址,不然值传递是修改不了的。
二 项目
2.1 猜数字
**需求:**生成一个[0, 100)的随机数,让用户猜这个数。程序会给出用户每次猜的结果是大还是小。
算法实现很简单就不说了,下面谈一下几个需要注意的问题。
首先是随机数,go的随机函数在math/rand这个包下面,使用随机函数的时候需要先设置随机种子,一般是以当前时间来设置。否则每次重新运行程序后随机的数字是一样的。
然后是输入的问题。用户输入是从控制台输入的,也就是标准输入os.Stdin。我们可以先利用stdin构造一个输入流,然后不断的从这个流里面读数据。就是样例代码里的写法。
除了这种复杂的写法,fmt包还提供了类似于c的scanf这种输入,可以直接从控制台输入。需要注意的是,这里要加个\n换行读掉输入的空行,否则在for里面用fmt.Scanf会把最后输入的回车也当作一次输入。
func main() {
rand.Seed(time.Now().UnixMilli())
num := rand.Intn(100)
for {
var number int
fmt.Scanf("%d\n", &number)
if number < num {
fmt.Println("小了")
} else if number > num {
fmt.Println("大了")
} else {
fmt.Println("猜对了")
break
}
}
}
2.2 翻译小程序
需求:用go实现一个单词翻译的程序。能将单词作为命令行参数输入,程序输出单词的中文含义。
主要的实现思路是用go发送翻译请求给翻译网站,然后解析返回的数据。
将请求转换成go代码:curlconverter.com/go/
根据服务器返回的json生成struct oktools.net/json2go
我们要做的只有:
- 利用os.Arg[1]读取main函数的参数,并作为需要翻译的单词
- 解析返回的数据,并找到翻译结果的字段打印出来即可