完成《A Tour of Go》的学习
我花了大约一个月的时间完成了Go语言的教程《A Tour of Go》。我使用的执行环境只是该网站内的playground工具。
借鉴的内容
-
- How to Write Go Code
-
- WEB+DB PRESS vol.82 はじめてのGo
- WEB+DB PRESS vol.95 Goによる並行処理
以下是各个问题所写的代码和笔记。
2016年11月13日开始
值得纪念的开始学习Go的一天。包。
2016年11月23日的課題是關於「For循環」和「牛頓法」。
处理牛顿法的问题。看到这个方程式突然就觉得糟糕。尽力获得正确的输出结果,但是却不使用for循环,而强行使用递归处理和全局变量等,无法理解出题者的意图…
package main
import (
"fmt"
"math"
)
var z = 1.0
var cnt = 0
func Sqrt(x float64) float64 {
zbuf := z
z = z - (z*z-x)/(2*z)
fmt.Println(cnt, z)
if math.Abs(zbuf-z) < 0.000001 {
return z
}
cnt++
return Sqrt(x)
}
func main() {
fmt.Println(Sqrt(3))
fmt.Println(math.Sqrt(3))
}
输出结果
0 2
1 1.75
2 1.7321428571428572
3 1.7320508100147276
4 1.7320508075688772
1.7320508075688772
1.7320508075688772
2016年11月26日的作业:切片
练习:切片
这个也很难,但是若有所思之后就做出来了。当出现漂亮的图像时,感到非常激动。
package main
import (
"golang.org/x/tour/pic"
)
func Pic(dx, dy int) [][]uint8 {
pic := make([][]uint8, dy)
for y := 0; y < dy; y++ {
pic[y] = make([]uint8, dx)
for x := 0; x < dx; x++ {
pic[y][x] = uint8((x+y)/2)
}
}
return pic
}
func main() {
pic.Show(Pic)
}

2016年11月26日的問題:地圖
练习:地图
地图的任务。在查看API参考文档的同时编写了代码。总算做完了。但是当我回头看代码时却搞不清楚它在做什么。
package main
import (
"strings"
"fmt"
"golang.org/x/tour/wc"
)
func WordCount(s string) map[string]int {
sf := strings.Fields(s)
fmt.Println(sf)
smap := make(map[string]int)
for _, elm := range sf {
fmt.Println(elm)
smap[elm] = smap[elm] + 1
}
return smap
}
func main() {
wc.Test(WordCount)
}
输出结果
[I am learning Go!]
I
am
learning
Go!
PASS
f("I am learning Go!") =
map[string]int{"I":1, "am":1, "learning":1, "Go!":1}
[The quick brown fox jumped over the lazy dog.]
The
quick
brown
fox
jumped
over
the
lazy
dog.
PASS
f("The quick brown fox jumped over the lazy dog.") =
map[string]int{"jumped":1, "the":1, "The":1, "quick":1, "brown":1, "fox":1, "over":1, "lazy":1, "dog.":1}
[I ate a donut. Then I ate another donut.]
I
ate
a
donut.
Then
I
ate
another
donut.
PASS
f("I ate a donut. Then I ate another donut.") =
map[string]int{"another":1, "I":2, "ate":2, "a":1, "donut.":2, "Then":1}
[A man a plan a canal panama.]
A
man
a
plan
a
canal
panama.
PASS
f("A man a plan a canal panama.") =
map[string]int{"man":1, "a":2, "plan":1, "canal":1, "panama.":1, "A":1}
2016/11/27的课题:闭包/斐波那契数列。
练习:斐波那契数列
记得当初我曾费很大劲,但最终成功了。如今回过头再看这段代码,仍然有些搞不明白(汗)
package main
import "fmt"
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
var f []int
return func() int {
switch len(f) {
case 0:
f = append(f, 0)
case 1:
f = append(f, 1)
default:
f = append(f, (f[len(f)-2] + f[len(f)-1]))
}
return f[len(f)-1]
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
输出结果 (Chū lì jié guǒ)
0
1
1
2
3
5
8
13
21
34
2016年12月11日的课题是:错误。
练习:错误
我记不太清楚了。大致上,我认为做得不错。
package main
import (
"fmt"
"math"
)
type ErrNegativeSqrt float64
func (e ErrNegativeSqrt) Error() string {
return fmt.Sprintf("cannot Sqrt negative number: %v",float64(e))
}
func Sqrt(x float64) (float64, error) {
var err ErrNegativeSqrt
if x < 0 {
err = ErrNegativeSqrt(x)
return 0, err
}
last_z, z := x, 1.0
for math.Abs(z-last_z) >= 1.0e-6 {
last_z, z = z, z-(z*z-x)/(2*z)
}
return z, nil
}
func main() {
fmt.Println(Sqrt(2))
fmt.Println(Sqrt(-2))
}
输出结果 (Chū lì jié guǒ)
1.4142135623730951 <nil>
0 cannot Sqrt negative number: -2
2016年12月11日的课题是《读者》。
练习:读者
请实现一个输出无限流ASCII字符 ‘A’ 的Reader类型。这个任务有点模糊不清,我不太记得了,不过好像做出来了。
package main
import "golang.org/x/tour/reader"
type MyReader struct{}
// TODO: Add a Read([]byte) (int, error) method to MyReader.
func (r MyReader) Read(b []byte) (int, error) {
for {
copy(b,"A")
return 1, nil
}
}
func main() {
reader.Validate(MyReader{})
}
输出结果
OK!
2016/12/11问题:将Reader进行包裹/rot13Reader
这是放弃了。无法完成。练习:rot13Reader。
2016年12月14日的課題是與Image介面有關。
练习:图像
虽然记不太清楚了,但是我通过查看API参考文档来模仿写出来的,结果成功了。
package main
import (
"golang.org/x/tour/pic"
"image"
"image/color"
)
type Image struct{}
// ColorModel returns the Image's color model.
func (img Image) ColorModel() color.Model {
return color.RGBAModel
}
// Bounds returns the domain for which At can return non-zero color.
// The bounds do not necessarily contain the point (0, 0).
func (img Image) Bounds() image.Rectangle {
return image.Rect(0, 0, 100, 100)
}
// At returns the color of the pixel at (x, y).
// At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
// At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
func (img Image) At(x, y int) color.Color {
return color.RGBA{0, 0, 255, 255}
}
func main() {
m := Image{}
pic.ShowImage(m)
}

2016年12月20日的课题是并行处理/二分树。
终于到了任务中最关键的并发处理问题。我花了大约三天时间来解决这个问题,最终还是放弃了。虽然我已经接近找到解决方法,但是非常沮丧,所以我在另一篇文章中详细写了这个情况。
2016年12月23日,最后的任务:并行处理/网络爬虫。
虽然不容易,但通过参考杂志文章和教程,我做到了。
package main
import (
"fmt"
"sync"
)
type Fetcher interface {
// Fetch returns the body of URL and
// a slice of URLs found on that page.
Fetch(url string) (body string, urls []string, err error)
}
// Crawl uses fetcher to recursively crawl
// pages starting with url, to a maximum of depth.
func Crawl(url string, depth int, fetcher Fetcher) {
c := SafeCounter{v: make(map[string]int)}
ch := make(chan string)
go InnerCrawl(url, depth, fetcher, ch , &c)
fmt.Println("<-ch", <-ch)
return
}
func InnerCrawl(url string, depth int, fetcher Fetcher, ch chan string, c *SafeCounter) {
c.Inc(url)
cnt := c.Value(url)
if cnt > 1 {
fmt.Printf("duplicate cnt:%v url:%s\n",cnt, url)
ch <- url
return
}
fmt.Println("depth:",depth)
if depth <= 0 {
ch <- url
return
}
body, urls, err := fetcher.Fetch(url)
if err != nil {
fmt.Println(err)
ch <- url
return
}
fmt.Printf("found: %s %q\n", url, body)
fmt.Printf("len(urls):%v\n", len(urls))
ich := make(chan string)
for _, u := range urls {
go InnerCrawl(u, depth-1, fetcher, ich, c)
}
for i := 0; i < len(urls); i++ {
fmt.Println("<-ich", <-ich)
}
ch <- url
return
}
func main() {
Crawl("http://golang.org/", 4, fetcher)
}
// fakeFetcher is Fetcher that returns canned results.
type fakeFetcher map[string]*fakeResult
type fakeResult struct {
body string
urls []string
}
func (f fakeFetcher) Fetch(url string) (string, []string, error) {
if res, ok := f[url]; ok {
return res.body, res.urls, nil
}
return "", nil, fmt.Errorf("not found: %s", url)
}
// fetcher is a populated fakeFetcher.
var fetcher = fakeFetcher{
"http://golang.org/": &fakeResult{
"The Go Programming Language",
[]string{
"http://golang.org/pkg/",
"http://golang.org/cmd/",
},
},
"http://golang.org/pkg/": &fakeResult{
"Packages",
[]string{
"http://golang.org/",
"http://golang.org/cmd/",
"http://golang.org/pkg/fmt/",
"http://golang.org/pkg/os/",
},
},
"http://golang.org/pkg/fmt/": &fakeResult{
"Package fmt",
[]string{
"http://golang.org/",
"http://golang.org/pkg/",
},
},
"http://golang.org/pkg/os/": &fakeResult{
"Package os",
[]string{
"http://golang.org/",
"http://golang.org/pkg/",
},
},
}
// SafeCounter is safe to use concurrently.
type SafeCounter struct {
v map[string]int
mux sync.Mutex
}
// Inc increments the counter for the given key.
func (c *SafeCounter) Inc(key string) {
c.mux.Lock()
// Lock so only one goroutine at a time can access the map c.v.
c.v[key]++
c.mux.Unlock()
}
// Value returns the current value of the counter for the given key.
func (c *SafeCounter) Value(key string) int {
c.mux.Lock()
// Lock so only one goroutine at a time can access the map c.v.
defer c.mux.Unlock()
return c.v[key]
}
输出结果
found: http://golang.org/ "The Go Programming Language"
not found: http://golang.org/cmd/
<-ich http://golang.org/cmd/
found: http://golang.org/pkg/ "Packages"
found: http://golang.org/pkg/os/ "Package os"
duplicate cnt:2 url:http://golang.org/pkg/
<-ich http://golang.org/pkg/
duplicate cnt:2 url:http://golang.org/
<-ich http://golang.org/
duplicate cnt:2 url:http://golang.org/cmd/
<-ich http://golang.org/cmd/
found: http://golang.org/pkg/fmt/ "Package fmt"
duplicate cnt:3 url:http://golang.org/pkg/
<-ich http://golang.org/pkg/
duplicate cnt:3 url:http://golang.org/
<-ich http://golang.org/
<-ich http://golang.org/pkg/os/
duplicate cnt:4 url:http://golang.org/
<-ich http://golang.org/
<-ich http://golang.org/pkg/fmt/
<-ich http://golang.org/pkg/
<-ch http://golang.org/
总结
这就结束了。如果写了奇怪的代码,请指出来,谢谢你。
Playground保存了代码,非常方便。但是在写这篇文章的过程中,回顾过去的代码时发现完全没有记忆,所以总体而言
让我们留下评论。
以上、我在现场(所见)的回报。