Head First Go - 第二部分条件和循环

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

本文是《Head First Go》的第二章,条件和循环



1. 调用方法

下面通过调用 time 包里面的 Time 类型的方法来获取年份

package main

import(
	"fmt"
	"time"
)

func main() {
	var now time.Time = time.Now()		//time.Now返回一个代表当前日期和时间的time.Time值
	var year int = now.Year()			//获取年, 调用now.Year方法
	fmt.Println(year)					//2022
}

方法是与特定类型的值关联的函数


strings包有一个 Replacer 类型,可以在字符串中搜索子字符串,并且在每次该字符串出现的地方用另一个字符串替换它。

package main

import (
	"fmt"
	"strings"
)

func main() {
	broken := "G# r#cks!"
	replacer := strings.NewReplacer("#", "o");	//将字符串中的#字符替换成o字符
	fixed := replacer.Replace(broken)			//进行替换
	fmt.Printf("fixed: %v\n", fixed)			//fixed: Go rocks!
}

now.Year() 和 strings.NewReplacer(“#”, “o”) 都是变量在左边,通过 . 的方式来调用方法名,方法名大写开头,意思是可以导入的。



2. 注释

两种注释方法:

package main

import (
	
)

func main() {
	//注释方法1:行注释
	/*
		注释方法2:块注释
	*/
}



3. 获取用户的分数

1. 输入数字

引出一个需求就是用户可以输入数字:

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	fmt.Print("Enter a grade: a")
	reader := bufio.NewReader(os.Stdin)			//设置从键盘获取文本的"缓冲读取器"
	input, _ := reader.ReadString('\n')			//返回用户输入的所有内容。直到按下<Enter>键为止
	fmt.Printf("input: %v\n", input)
}

首先,我们需要让用户知道需要输入某些东西,所以我们使用fmt.Print函数来显示一个提示符。接下来从bufio.NewReader(os.Stdin)中获取标准输入bufio.Reader,调用 Reader 的 ReadString 方法。ReadString 方法需要一个带有 rune 字符的参数,意思是遇到这个字符就停止读取,所以我们给了 ‘\n’,只要遇到 ‘\n’ 就停止读取,只读取 ‘\n’ 之前的字符,最后打印出来。
在这里插入图片描述



但是如果我们改一下:input, _ := reader.ReadString('\n') 改成 input := reader.ReadString('\n'), 就会报错,因为函数有两个返回值,而我们只是获取了其中一个
在这里插入图片描述


在Go语言中,一个函数可以返回任意数量的值,Go中多个返回值最常见的用法就是返回一个额外的错误值,可以通过查询该错误来确定函数或方法运行时是否发生了错误,举几个例子:

	b, err := strconv.ParseBool("true")			//如果字符串无法转换未布尔值
	f, err2 := os.Open("myfile.txt")			//如果文件无法打开,就返回一个错误
	r, err3 := http.Get("heep://golang.org")	//如果无法检索页面,就返回错误

回到上面的代码,如果我们只是使用一个变量接收函数返回值,就会报错
在这里插入图片描述


2. 解决方法

第一个解决方法是使用空白标识符忽略错误返回值,也就是上面用的那种。当我们有一个值,通常会分配给一个变量,但是我们不打算使用时,可以使用Co的空白标识符,只需要在赋值语句中输入一个下划线(_)字符,就可以忽略这个返回值了。但是有一个弊端就是我们无法解决错误,因为不管有没有错误,程序都会继续执行。


第二个解决方法是解决错误。 log 包下面有一个 Fatal 函数,它可以同时为我们完成这两项操作:将一条消息记录到终端并停止程序运行。(Fatal意味者报告一个错误,并 “杀死” 你的程序)
在这里插入图片描述



4. 条件

按照上面的例子,虽然我们输出了err,但是程序无论正确与否都会停止运行,所以我们需要使用条件来判断。首先 Go 的 if 语法if 1 < 2 { 逻辑 }。和 java 的不同点就是 Go 可以省略括号,有了这个语法,我们可以把程序改造成下面的这样。

package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
)

func main() {
	fmt.Print("Enter a grade: ")
	reader := bufio.NewReader(os.Stdin)			//设置从键盘获取文本的"缓冲读取器"
	input, err := reader.ReadString('\n')			//返回用户输入的所有内容。直到按下<Enter>键为止
	if(err != nil){
		log.Fatal(err)
	}
	fmt.Printf("input: %v\n", input)
}

此外,简单介绍下 if 用法:与或非

package main

import "fmt"

func main() {
	if 3 > 2 {
		fmt.Println("1 == 1")
	}

	if 2 < 1{
		fmt.Println("1 == 2")
	}

	if true && false {
		fmt.Println("true && false")
	}

	if true || false {
		fmt.Println("true || false")
	}

	if !false {
		fmt.Println("!false")
	}

	/*
		1 == 1
		true || false	
		!false
	*/
}



5. 避免遮盖名字

和 java 一样,尽量不要把变量写成和类型名称相同,同样也不要写成和函数名相同。下面的例子就可以看到了,如果我们提前声明了 int 名字的类型,那么下面再声明 int 类型变量的时候这个 int 就是变量名而不是 int 类型了。

package main

import "fmt"

func main() {
	var int int = 12
	var append string = "minutes of bonus footage"
	var fmt string = "DVD"
	var count int 			//报错int (variable of type int) is not a type
	fmt.println(int, append. fmt, count);
}



6. 将字符串转换为数字

接着上面的例子,我们现在要输入一个数字,然后把这个字符串转化成数字类型的数据,最终比较。下面流程

  • 首先使用 strings 包下面的 TrimSpace 函数,删除字符串开头和结尾的所有空白字符(‘\n’,‘\t’,’ ')
  • 然后使用 strconv 包下的 ParseFloat 方法转化字符串
  • 最终输出即可
package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
)

func main() {
	fmt.Print("Enter a grade: ")
	reader := bufio.NewReader(os.Stdin)			//设置从键盘获取文本的"缓冲读取器"
	input, err := reader.ReadString('\n')			//返回用户输入的所有内容。直到按下<Enter>键为止
	if(err != nil){
		log.Fatal(err)
	}
	input = strings.TrimSpace(input)
	f, err2 := strconv.ParseFloat(input, 64)
	if(err2 != nil){
		log.Fatal(err2)
	}
	var status string
	if f >= 60{
		status = "大于60分"
	}else{
		status = "小于60分"
	}
	fmt.Printf(status)
	//Enter a grade: 90
	//大于60分
}



7. 块

Go代码可以分成块,也就是代码段。块通常由({ })包围,尽管在源代码文件和包级别也有块。块可以彼此嵌套。
在这里插入图片描述
注意的是在 if 块中声明的变量在 if 块外部无法使用。



8. 块和变量的作用域

变量的作用域由其声明所在的块和嵌套在块中的任何块组成

package main

import "fmt"

var packageVar = "package"		//作用域整个main函数

func main() {
	var functionVar = "funcation"		//作用域是main函数
	if true {
		var condition = "conditional"	//作用域是if块
		fmt.Println(condition)
		fmt.Println(functionVar)
		fmt.Println(packageVar)
	}
	fmt.Println(functionVar)
	fmt.Println(packageVar)
}

//conditional
//funcation
//package
//funcation
//package
  • package作用域是整个main包
  • functionVar作用域是它声明的整个函数
  • condition 作用域仅限于 if 块,在 if 块之外使用会报错(undeclared name: condition)



9. 短变量声明中只有一个变量必须是新的

来看这一段代码

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	s, err := reader.ReadString('\n')
	f, err := strconv.ParseFloat(strings.TrimSpace(s), 64)
	fmt.Printf("f: %v\n", f)
	fmt.Printf("err: %v\n", err)
}


可以看到里面 err 中短变量声明了两次,确实,当同一个变量名在同一个作用域中被声明了两次的时候,我们会得到一个编译错误

a := 1
a := 1

但是只要短变量声明中至少有一个变量名是新的,这是允许的。新变量名被视为声明,而现有的名字被视为赋值。如下例子:a 和 b 在下面的语句中,a 和 b 被重新赋值,这里不是声明的含义,Go 语言允许这样的语法。

package main

import (
	"fmt"
)

func main() {
	a := 1
	a, b := 2, 3
	b, c := 3, 4
	fmt.Printf("a: %v\n", a)			//a: 2
	fmt.Printf("b: %v\n", b)			//b: 3
	fmt.Printf("c: %v\n", c)			//c: 4

}



10. 创建一个游戏

  • 生成一个 1 到 100 之间的随机数,并将其存储为目标数,供玩家猜测
  • 提示玩家猜测目标数是什么,并存储他们的回答
  • 如果玩家猜测小于目标树,输入 “低了” ,高于就输出 “高了”
  • 允许玩家猜测10次,在每次猜之前,让他们知道还剩下多少次
  • 如果猜测的数和目标树相同提示正确
  • 如果玩家猜测次数用完了也没有猜出,提示次数使用完



11. 包名和导入路径

package main

import (
	"fmt"
	"math/rand"
)

func main() {
	target := rand.Intn(100) + 1	
	fmt.Printf("target: %v\n", target)	//target: 82
}

"math/rand" 导入 math. rand 包,fmt 导入 fmt 包,类似于磁盘上面的路径,下面举一个例子

导入路径包名
“archive”archive
“archive/tar”tar
“archive/zip”zip
“math”math
“math/cmplx”cmplx
“math/rand”rand



12. 生成随机数

导入之后,直接使用 rand 包直接调用函数生成随机数。rand.Intn 返回一个介于 0 和你提供的数字之间的随机整数。也就是说如果我们传入100,那么结果会获得一个 0 ~ 99 之间的随机数,我们需要 1 ~ 100 之间的,那么就在原来基础上 +1 就行了。

但是值得注意的是,我们在程序直接调用之后生成的一直都是一个数,那么我们要生成不同的随机数,就要通过 rand.Seed 函数传递一个种子,从而生成不同的随机数

package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	seconds := time.Now().Unix()			//获取当前日期和时间的整数形式
	rand.Seed(seconds)						//设置种子
	target := rand.Intn(100) + 1
	fmt.Printf("target: %v\n", target)		//target: 22
}



13. for 循环

这个游戏里面有一个需求是玩家最多能猜测 10 次,对于这个请求,我们可以使用 for 循环

for x := 4; x <= 10; x++{
	//代码块
}

同样的,x++(每次自增+1),x–(每次减少1),x += 等语法都可以使用,而且同样的 for 循环变量的作用域不能在循环外面使用。语法和 java 的一样,只是少了括号,Go语言不需要加上括号,同时也不允许加上括号

package main

import (
	"fmt"
	// "math/rand"
	// "time"
)

func main() {
	var i = 0
	for i = 0; i < 10; i++{
		y := 1				//y只能在for循环中使用
		fmt.Printf("y: %v\n", y)	//只能在for循环之外访问
		fmt.Printf("i: %v\n", i)
	}
	//i: 0
	//i: 1
	//i: 2
	//i: 3
	//i: 4
	//i: 5
	//i: 6
	//i: 7
	//i: 8
	//i: 9
	
}



14. 使用 continue 和 break 跳过部分循环

continue:跳过本次循环,进入下一次循环
break:跳出本层循环

下面简单写个例子:

package main

import (
	"fmt"
	// "math/rand"
	// "time"
)

func main() {
	for i := 0; i < 10; i++ {
		if i == 2{
			continue  //遇到2就跳过
		}
		fmt.Print(i, " ")	
	}
	//结果:0 1 3 4 5 6 7 8 9


	fmt.Println();
	for i := 0; i < 10; i++ {
		if i == 2{
			break  //遇到2就退出
		}
		fmt.Print(i, " ")	
	}
	//结果:0 1 

}



15. 最终的代码

最终来整体写一下第10题的代码

package main

import (
	"bufio"
	"fmt"
	"log"
	"math/rand"
	"os"
	"strconv"
	"strings"
	"time"
)

func main() {
	seconds := time.Now().Unix()	//获取秒
	rand.Seed(seconds)				//设置时间种子
	target := rand.Intn(100)+1;		//设置目标数

	fmt.Println("现在已经生成一个数,是在 1 ~ 100 之间,你能猜出来吗");

	reader := bufio.NewReader(os.Stdin)	//创建一个reader
	success := false					//是否成功了

	for start := 0; start < 10; start++{
		fmt.Println("现在你还有" , (10-start) , "次机会, 请输入一个数:");
		input, err := reader.ReadString('\n')	//读取用户输入的数字
		if err != nil{
			log.Fatal(err);
		}

		input = strings.TrimSpace(input)
		//把数的数字转化为整数
		res, err := strconv.Atoi(input)
		if err != nil{
			log.Fatal(err);
		}

		if res > target{
			fmt.Println("你输入的数据比目标值要大");
		}else if res < target {
			fmt.Println("你输入的数据比目标值要小");
		}else{
			success = true;		//设置为true
			fmt.Println("恭喜你找到了!!!");
			break;				//退出循环
		}

	}

	if !success {
		fmt.Println("你没有找到目标值!!!");
	}
	/*
		现在已经生成一个数,是在 1 ~ 100 之间,你能猜出来吗
		现在你还有 10 次机会, 请输入一个数:
		98
		你输入的数据比目标值要大
		现在你还有 9 次机会, 请输入一个数:
		50
		你输入的数据比目标值要大
		现在你还有 8 次机会, 请输入一个数:
		25
		你输入的数据比目标值要大
		现在你还有 7 次机会, 请输入一个数:
		12
		你输入的数据比目标值要小
		现在你还有 6 次机会, 请输入一个数:
		20
		你输入的数据比目标值要小
		现在你还有 5 次机会, 请输入一个数:
		23
		你输入的数据比目标值要大
		现在你还有 4 次机会, 请输入一个数:
		22
		恭喜你找到了!!!
	*/
}






如有错误,欢迎指出!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值