go基础学习及课后作业 | 青训营笔记

93 阅读2分钟

这是我参与「第五届青训营 」笔记创作活动的第一天。

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 实现另一个翻译引擎接口——金山词霸

查看翻译请求接口如下图所示:

image.png 查看请求参数见下图,请求paylod是参数字符为from=en&to=zh&q=:

image.png 因为不是格式化的json,所以在拼接请求时直接使用字符串拼接,代码如下:

var data = strings.NewReader(`from=en&to=zh&q=` + word)

查看响应json(见下图),可知翻译字段在content.out字段:

image.png 返回并输出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)
   }
}

image.png 如何让主线程去等待子协程结束呢? 我是这样子做的:首先定义全局变量var wg sync.WaitGroup,在开启子协程前进行wg.Add(1)操作,同时也在query()方法内部添加一个defer wg.Done()的延迟方法。这样就解决了主线程提示语句会先于子协程输出的问题。 最终结果截图:

image.png