这是我参与「第五届青训营 」笔记创作活动的第一天。
1 go基础学习
1.2 变量与常量
go语言常变量名由字母、数字、下划线组成,注意:首个字符不能为数字。 变量声明关键字:var;常量声明关键字:const。
变量声明
//标准声明格式,默认值为“”
var value String = "conason"
//根据赋值类型推导,value的类型如下就是String
var value = "conaosn"
//隐式声明
value := "conason"
//多变量声明
var v1,v2 String
//多变量赋值
var v1 String
var v2 int
v1,v2 = "conason",77
1.3 循环
go语言中只有for循环,没有while循环
循环格式与Java类似,差别在于go-for条件语句没有{}包裹并且条件语句可省略,具体如下
//死循环
for {
fmt.Println("loop")
}
//for循环
for i := 0; i < 3; i++ {
if i == 2 {
continue
}
fmt.Println(i)
}
//可省略条件
var i int = 6
for i < 7 {
if i > 0 {
break
}
fmt.Println(i)
i = i -1
}
1.4 条件(if、switch)
if条件语句与Java类似,区别在于go条件部分没有{}包裹,需要注意到的是在go语言不支持三元运算。
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")
}
switch语句,不同于Java,其case匹配后默认break,如需继续匹配后续case可以使用fallthrough
a := 2
switch a {
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
case 3:
fmt.Println("three")
case 4, 5:
fmt.Println("four or five")
default:
fmt.Println("other")
}
1.5 数组与切片
数据与切片的关系就类似于Java中数据与ArrayList的关系 数组的声明格式
//声明一个长度为5的int数组
var a [5]int
切片的声明格式
//声明一个长度未知的int类型切片
var arr []int
//使用make函数创建容量capacity为100,长度为3的int类型切片,capacity参数为可选参数
slice := make([]int,3,100)
1.6 map
类似于Java中的hashMap集合,map也是键值型数据类型。 创建一个string型键,int型值的map
//声明
var m map[string]int
//make函数
m := make(map[string]int)
存取map
//添加键值对
m["one"] = 2
//取出元素
value,ok := map["one"]
if ok {
fmt.Println(value)
}else{
fmt.Println("no such key")
}
1.7 range
类似于Java中的Iterator,range可以迭代集合(数组、切片、map、channel)并返回元素对应索引和索引对应的值,以map为例循环迭代代码如下
map = make(map[string]int)
for index,value := range map{
fmt.Println("It's key:",index)
fmt.Println("It's value:", value)
}
1.8 struct结构体
结构体是特定数据类型的集合,类似于Java中的实体类,但是go中并没有重载、继承、多态等特性。 struct声明:
//定义一个名字结构体
type name struct {
firstName string
lastName string
}
struct赋值与取值
//赋值
n := name(firstNmae:"居易",lastName:"白")
//另一种方式赋值
var n name
n.firstName = "居易"
n.lastName = "白"
//取值
fmt.Println("firstName:",n.firstName)
2 课后作业
2.1 猜字游戏——使用Scanf()函数完成输入处理
非常简单的一道课后作业,不过值得注意的是,使用Scanf()函数也会解析换行符为0,因此需要冗余变量a来截取换行符使其不参与猜字,具体实现见代码。
func main() {
maxNum := 100
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(maxNum)
for {
fmt.Println("Please input your guess")
//使用冗余变量a截取出换行符
var guess, a int
fmt.Scanf("%d%d", &guess, &a)
fmt.Println("You guess is", guess)
if guess > secretNumber {
fmt.Println("Your guess is bigger than the secret number. Please try again")
} else if guess < secretNumber {
fmt.Println("Your guess is smaller than the secret number. Please try again")
} else {
fmt.Println("Correct, you Legend!")
break
}
}
}
2.2 实现另一个翻译引擎接口——金山词霸
查看翻译请求接口如下图所示:
查看请求参数见下图,请求paylod是参数字符为
from=en&to=zh&q=:
因为不是格式化的json,所以在拼接请求时直接使用字符串拼接,代码如下:
var data = strings.NewReader(`from=en&to=zh&q=` + word)
查看响应json(见下图),可知翻译字段在content.out字段:
返回并输出content.out字段,代码如下:
err = json.Unmarshal(bodyText, &dictResp)
if err != nil {
log.Fatal(err)
}
if dictResp.Content.Out == "" {
fmt.Println("无翻译")
return
}
fmt.Println("中文翻译:", dictResp.Content.Out)
2.3 实现并行请求
简单实现:直接使用go关键字开启一个子协程。弊端:main线程总会先打印输入提示,代码如下:
func main() {
for {
fmt.Println("请输入待翻译英文:")
var word, ln string
fmt.Scanf("%s%s", &word, &ln)
//ifanyi()为金山词霸翻译请求接口
ifanyi(word)
//开启一个协程请求彩云翻译接口
go query(word)
}
}
如何让主线程去等待子协程结束呢?
我是这样子做的:首先定义全局变量
var wg sync.WaitGroup,在开启子协程前进行wg.Add(1)操作,同时也在query()方法内部添加一个defer wg.Done()的延迟方法。这样就解决了主线程提示语句会先于子协程输出的问题。
最终结果截图: