Go 语言之旅:习题解答之基础模块

·  阅读 194

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情

前言

之前在学习 Go 的官网教程时,发现它里面的练习好像没有答案,所以在这里分享一下自己写的解答,给新入门的 Gopher 提供一个对照,如果有疑问或者有更好的方法,欢迎大家在评论区里一起讨论。

英文版:A Tour of Go

中文版:Go 语言之旅

基础模块

循环与函数

英文版:golang.google.cn/tour/flowco…

中文版:tour.go-zh.org/flowcontrol…

题目简述

一句话概括就是:用牛顿法实现平方根函数。

xx 的平方根,从某个猜测的值 zz 开始,我们可以根据 z2z^2xx 的近似度来调整 zz,产生一个更接近的猜测:

z -= (z*z - x) / (2*z)
复制代码

重复调整的过程,猜测的结果会越来越精确,得到的答案也会尽可能接近实际的平方根的值。

上面的 z2xz^2-xz2z^2 到它所要到达的值(即 xx)的距离, 除以的 2z2zz2z^2 的导数,我们通过 z2z^2 的变化速度来改变 zz 的调整量。这种通用方法叫做牛顿法,它对很多函数,特别是平方根而言非常有效。

解答

package main

import (
	"fmt"
	"math"
)

func Sqrt(x float64) float64 {
	z := x / 2
	d := 1.0
	for math.Abs(d) > 1e-15 {
		d = (z*z - x) / (2 * z)
		z -= d
		fmt.Println(z)
	}
	return z
}

func main() {
	v:=2.0
	fmt.Println("custom:",Sqrt(v))
	fmt.Println("math:",math.Sqrt(v))
}
复制代码

初值 zz 可设为任意值(需保证为 float64 类型,或者进行类型转换),然后给改变量 d 设置一个很小的阈值,来使结果更加准确。迭代的次数与设置的初始值以及阈值有关。

切片

英文版:golang.google.cn/tour/morety…

中文版:tour.go-zh.org/moretypes/1…

题目简述

实现 Pic。它应当返回一个长度为 dy 的切片,其中每个元素是一个长度为 dx,元素类型为 uint8 的切片。当你运行此程序时,它会将每个整数解释为蓝度值并显示它所对应的图像。

设每一位置的值为 v,pic 包实际上调用了 image.NewNRGBA(),然后令 R=v, G=v, B=255, A=255,所以是蓝度值。

解答

package main

import "golang.org/x/tour/pic"

func Pic(dx, dy int) [][]uint8 {
	img := make([][]uint8, dy)
	for y := range img {
		img[y] = make([]uint8, dx)
		for x := range img[y] {
			img[y][x] = uint8((x + y) / 2)
		}
	}
	return img
}

func main() {
	pic.Show(Pic)
}
复制代码

初学者需要注意的一点是,二维切片中的每一项元素必须单独创建并初始化。

如果显示的是 base64 编码,可以通过这个网站转为图像: base64-to-image.com/

yqlwq9n466__2022_8_11.png

(x + y) / 2 的图像

切片2.png

x % (y + 1) 的图像

映射

英文版:golang.google.cn/tour/morety…

中文版:tour.go-zh.org/moretypes/2…

题目简述

实现 WordCount。它应当返回一个映射,其中包含字符串 s 中每个“单词”的个数。函数 wc.Test 会对此函数执行一系列测试用例,并输出成功还是失败。

解答

package main

import (
	"golang.org/x/tour/wc"
	"strings"
)

func WordCount(s string) map[string]int {
	mp := make(map[string]int)
	words := strings.Fields(s)
	for _, v := range words {
		mp[v]++
	}
	return mp
}

func main() {
	wc.Test(WordCount)
}
复制代码

strings.Fields() 会分割被空白字符围绕的字符串,然后返回一个字符串切片。遍历切片,统计字符串个数即可。这里可能会有人想用 ,ok 来检查字符串是否已经在映射中,然后分两种情况操作,这样也可以。但实际上, make 在创建映射时已经帮我们把空间初始化为零值,我们可以很方便地直接使用它。

斐波纳契闭包

英文版:golang.google.cn/tour/morety…

中文版:tour.go-zh.org/moretypes/2…

题目简述

实现一个 fibonacci 函数,它返回一个函数(闭包),该闭包返回一个斐波纳契数列 (0, 1, 1, 2, 3, 5, ...)

解答

package main

import "fmt"

func fibonacci() func() int {
	i := 0
	a, b := 0, 1
	return func() int {
		if i == 0 {
			i++
			return 0
		} else {
			a, b = b, a+b
			return a
		}
	}
}

func main() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}
复制代码

由于数列是从 0 开始的,所以我们需要一个额外的标记,来给第一次操作做特判。或者你也可以使用以下的形式:

func fibonacci() func() int {
	a, b, c := 0, 0, 1
	return func() int {
		a, b, c = b, c, b+c
		return a
	}
}
复制代码

这种形式看起来更简洁一些。

总结

本篇文章是对基础模块的习题解答,包括循环、切片、映射和闭包的知识。如果大家有更好的答案,欢迎在评论区留言。

最后,如果本篇文章对你有所帮助,求 点赞、收藏、评论,感谢支持 ✧(≖ ◡ ≖✿

分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改