《Go 语言之旅》是一个不错的 Golang 教程,适合拥有其他语言的编程经验、但是没有学过 Golang 的同学学习。该教程中含有一些简单的练习题,通过动手写代码的方式达到快速巩固知识点的目的。
本文是《Go 语言之旅》中“基础(Basics)”章节中的练习题,并附上了我自己在学习这部教程时写出的解答代码,供大家参考。
教程其他章节的练习题解答可以点击链接查看:
练习:循环与函数
题目
为了练习函数与循环,我们来实现一个平方根函数:用牛顿法实现平方根函数。
计算机通常使用循环来计算 x 的平方根。从某个猜测的值 z 开始,我们可以根据 z² 与 x 的近似度来调整 z,产生一个更好的猜测:
z -= (z*z - x) / (2*z)
重复调整的过程,猜测的结果会越来越精确,得到的答案也会尽可能接近实际的平方根。
在提供的
func Sqrt
中实现它。无论输入是什么,对 z 的一个恰当的猜测为 1。 要开始,请重复计算 10 次并随之打印每次的 z 值。观察对于不同的值 x(1、2、3 ...), 你得到的答案是如何逼近结果的,猜测提升的速度有多快。提示:用类型转换或浮点数语法来声明并初始化一个浮点数值:
z := 1.0 z := float64(1)
然后,修改循环条件,使得当值停止改变(或改变非常小)的时候退出循环。观察迭代次数大于还是小于 10。 尝试改变 z 的初始猜测,如 x 或 x/2。你的函数结果与标准库中的 math.Sqrt 接近吗?
解答
package main
import (
"fmt"
"math"
)
func Sqrt(x float64) float64 {
z := 1.0 // 猜测初始值
prev := 0.0 // 上次迭代的结果
for math.Abs(z-prev) > 1e-5 { // 当值改变非常小的时候退出循环
prev = z
z -= (z*z - x) / (2 * z)
}
return z
}
func main() {
fmt.Println(Sqrt(2))
fmt.Println(math.Sqrt(2)) // 与标准库函数的结果比较
}
运行结果如下,可以看到自己实现的 Sqrt
与标准库 math.Sqrt
给出的结果相近。
1.4142135623746899
1.4142135623730951
练习:切片
题目
实现
Pic
。它应当返回一个长度为dy
的切片,其中每个元素是一个长度为dx
,元素类型为uint8
的切片。当你运行此程序时,它会将每个整数解释为灰度值(好吧,其实是蓝度值)并显示它所对应的图像。图像的选择由你来定。几个有趣的函数包括
(x+y)/2
,x*y
,x^y
,x*log(y)
和x%(y+1)
。(提示:需要使用循环来分配
[][]uint8
中的每个[]uint8
;请使用uint8(intValue)
在类型之间转换;你可能会用到math
包中的函数。)
解答
package main
import "golang.org/x/tour/pic"
func Pic(dx, dy int) [][]uint8 {
image := make([][]uint8, dy)
for y := range image { // 外层循环,对于每一行
image[y] = make([]uint8, dx) // 创建这一行的切片
for x := range image[y] { // 内层循环,对于一行中的每一列
image[y][x] = uint8(x ^ y) // 修改这里以产生不同的图像
}
}
return image
}
func main() {
pic.Show(Pic)
}
运行结果如下。另外,修改第 10 行的公式(见题目),可以产生不同的图像。
本文地址:https://www.jeddd.com/article/a-tour-of-go-exercises-basics.html
练习:映射
题目
实现
WordCount
。它应当返回一个映射,其中包含字符串s
中每个“单词”的个数。函数wc.Test
会对此函数执行一系列测试用例,并输出成功还是失败。你会发现 strings.Fields 很有帮助。
解答
package main
import (
"golang.org/x/tour/wc"
"strings"
)
func WordCount(s string) map[string]int {
mapping := make(map[string]int)
wordlist := strings.Fields(s) // 用空格分割为单词的切片
for _, word := range wordlist {
mapping[word] += 1 // 默认为0,所以可以直接+1
}
return mapping
}
func main() {
wc.Test(WordCount)
}
运行结果如下,可以通过测试。
PASS
f("I am learning Go!") =
map[string]int{"Go!":1, "I":1, "am":1, "learning":1}
PASS
f("The quick brown fox jumped over the lazy dog.") =
map[string]int{"The":1, "brown":1, "dog.":1, "fox":1, "jumped":1, "lazy":1, "over":1, "quick":1, "the":1}
PASS
f("I ate a donut. Then I ate another donut.") =
map[string]int{"I":2, "Then":1, "a":1, "another":1, "ate":2, "donut.":2}
PASS
f("A man a plan a canal panama.") =
map[string]int{"A":1, "a":2, "canal":1, "man":1, "panama.":1, "plan":1}
练习:斐波那契闭包
题目
让我们用函数做些好玩的事情。
实现一个
fibonacci
函数,它返回一个函数(闭包),该闭包返回一个斐波纳契数列(0, 1, 1, 2, 3, 5, ...)
。
解答
package main
import "fmt"
// 返回一个“返回int的函数”
func fibonacci() func() int {
prev, current := -1, 1 // 初始值可由期待产生的序列倒推出来
return func() int {
prev, current = current, prev+current
return current
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
运行结果如下。
0
1
1
2
3
5
8
13
21
34
References
本文地址:https://www.jeddd.com/article/a-tour-of-go-exercises-basics.html