A Tour of Go 的练习题目
练习:循环和函数
package main
import (
"fmt"
"math"
)
const eps = 1e-9
func Sqrt(x float64) float64 {
z := 1.0
p := z
for {
z = z - (z * z - x) / (2 * z)
if math.Abs(z - p) < eps {
break
}
p = z
}
return z
}
func main() {
fmt.Println(math.Sqrt(2))
fmt.Println(Sqrt(2))
}
运动:薄片
package main
import "code.google.com/p/go-tour/pic"
func Pic(dx, dy int) [][]uint8 {
image := make([][]uint8, dy)
for y := range image {
image[y] = make([]uint8, dx)
}
for y := 0; y < dy; y++ {
for x :=0; x < dx; x++ {
image[y][x] = uint8((x + y) / 2)
}
}
return image
}
func main() {
pic.Show(Pic)
}
锻炼:地图
package main
import (
"code.google.com/p/go-tour/wc"
"strings"
)
func WordCount(s string) map[string]int {
countMap := map[string]int{}
for _, word := range strings.Fields(s) {
countMap[word]++
}
return countMap
}
func main() {
wc.Test(WordCount)
}
练习:斐波那契闭包
package main
import "fmt"
func fibonacci() func() int {
a, b := 0, 1
return func() int {
a, b = b, a + b
return a
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
高级练习:复杂立方根
package main
import (
"fmt"
"math/cmplx"
)
const eps = 1e-9
func Cbrt(x complex128) complex128 {
z := 1 + 0i
p := z
for {
z = z - (z * z * z - x) / (3 * z * z)
if cmplx.Abs(z - p) < eps {
break
}
p = z
}
return z
}
func main() {
fmt.Println(cmplx.Pow(2 + 5i, 1.0/3))
fmt.Println(Cbrt(2 + 5i))
}
练习:错误
package main
import (
"fmt"
"math"
)
type ErrNegativeSqrt float64
func (e ErrNegativeSqrt) Error() string {
return fmt.Sprintf("cannot Sqrt negative number: %f", e)
}
const eps = 1e-9
func Sqrt(x float64) (float64, error) {
if x < 0 {
return 0, ErrNegativeSqrt(x)
}
z := 1.0
p := z
for {
z = z - (z * z - x) / (2 * z)
if math.Abs(z - p) < eps {
break
}
p = z
}
return z, nil
}
func main() {
fmt.Println(Sqrt(2))
fmt.Println(Sqrt(-2))
}
练习:HTTP 处理程序
package main
import (
"fmt"
"net/http"
)
type String string
func (s String) ServeHTTP(w http.ResponseWriter, r *http.Request){
fmt.Fprintf(w, "%s", s)
}
type Struct struct {
Greeting string
Punct string
Who string
}
func (s *Struct) ServeHTTP(w http.ResponseWriter, r *http.Request){
fmt.Fprintf(w, "%s", s.Who + s.Punct + s.Greeting)
}
func main() {
http.Handle("/string", String("I like takoyaki"))
http.Handle("/struct", &Struct{"Hello", ":", "Sam"})
http.ListenAndServe(":4000", nil)
}
锻炼:图片
package main
import (
"code.google.com/p/go-tour/pic"
"image"
"image/color"
)
type Image struct{}
func (im *Image) ColorModel() color.Model {
return color.RGBAModel
}
func (im *Image) Bounds() image.Rectangle {
return image.Rectangle{
image.Point{0, 0},
image.Point{200, 200},
}
}
func (im *Image) At(x, y int) color.Color {
return color.RGBA{uint8(x % 256), uint8(y % 256), uint8((x * y) % 256 ), 255}
}
func main() {
m := Image{}
pic.ShowImage(&m)
}
练习:Rot13阅读器
package main
import (
"io"
"os"
"strings"
)
type rot13Reader struct {
r io.Reader
}
func rot13(b byte) byte {
if 'A' <= b && b <= 'Z' {
k := b - 'A'
return 'A' + (k - 13 + 26) % 26
}
if 'a' <= b && b <= 'z' {
k := b - 'a'
return 'a' + (k - 13 + 26) % 26
}
return b
}
func (rot *rot13Reader) Read(p []byte) (int, error){
nr, ne := rot.r.Read(p)
if ne != nil {
return nr, ne
}
for i:=0; i<nr; i++ {
p[i] = rot13(p[i])
}
return nr, nil
}
func main() {
s := strings.NewReader(
"Lbh penpxrq gur pbqr!")
r := rot13Reader{s}
io.Copy(os.Stdout, &r)
}
练习:等价的二进制树
http://go-tour-jp.appspot.com/#70
在这个网址上,你可以参观一个Go语言的教学网站,它教你如何创建等价的二叉树。
http://stackoverflow.com/questions/12224042/go-tour-exercise-equivalent-binary-trees
这个问题在Stack Overflow上问到了如何使用Go语言来练习创建等价的二叉树。
package main
import "code.google.com/p/go-tour/tree"
import "fmt"
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int){
var walker func(*tree.Tree)
walker = func(t *tree.Tree) {
if t.Left != nil {
walker(t.Left)
}
ch <- t.Value
if t.Right != nil {
walker(t.Right)
}
}
walker(t)
close(ch)
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
c1 := make(chan int)
c2 := make(chan int)
go Walk(t1, c1)
go Walk(t2, c2)
for {
n1, ok1 := <-c1
n2, ok2 := <-c2
if n1 != n2 || ok1 != ok2 {
return false
}
if !ok1 {
break
}
}
return true
}
func main() {
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(5), tree.New(5)))
fmt.Println(Same(tree.New(3), tree.New(2)))
}
练习:网络爬虫
http://go-tour-jp.appspot.com/#71 可以让您在浏览器中学习Go编程语言的互动教程。该教程涵盖了Go语言的语法、数据类型、函数等内容,并提供了许多实践性的例子和练习。
http://c4se.hatenablog.com/entry/2013/01/24/175114 是一篇关于Go编程语言的博文。在这篇博文中,作者介绍了Go的一些特性和优势,并分享了自己的学习心得和体会。如果您对Go编程感兴趣,这篇博文可以作为您的参考资料。
在另一个版本中,修正了当深度小于等于0时的处理方式。
package main
import (
"fmt"
"time"
)
type Fetcher interface {
Fetch(url string) (body string, urls []string, err error)
}
func Crawl(url string, depth int, fetcher Fetcher) {
type URL struct {
url string
depth int
}
msg := make(chan string)
req := make(chan URL)
quit := make(chan int)
crawler := func (url string, depth int) {
defer func() { quit <- 0 }()
if depth <= 0 {
return
}
body, urls, err := fetcher.Fetch(url)
if err != nil {
msg <- fmt.Sprintf("%s\n", err)
return
}
msg <- fmt.Sprintf("found: %s %q\n", url, body)
for _, u := range urls {
req <- URL{ u, depth - 1 }
}
}
works := 1
memo := make(map[string]bool)
memo[url] = true
go crawler(url, depth)
for works > 0 {
select {
case s := <-msg:
fmt.Print(s)
case u := <-req:
if !memo[u.url] {
memo[u.url] = true
works++
go crawler(u.url, u.depth)
}
case <- quit:
works--
}
}
}
func main() {
Crawl("http://golang.org/", 4, fetcher)
}
type fakeFetcher map[string]*fakeResult
type fakeResult struct {
body string
urls []string
}
func (f fakeFetcher) Fetch(url string) (string, []string, error) {
time.Sleep(time.Second * 5)
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/",
},
},
}
练习:网络爬虫 另一个版本
由于上面的版本会被阻止,所以我也写了一个不被阻止的版本。
另外,处理 depth <= 0 的地方有错误,所以我也做出了修正。
感觉这个版本更清爽一些。
package main
import (
"fmt"
"time"
)
type Fetcher interface {
Fetch(url string) (body string, urls []string, err error)
}
func Crawl(url string, depth int, fetcher Fetcher) {
type Msg struct {
message string
}
type URL struct {
url string
depth int
}
type Quit struct{}
ch := make(chan interface{}, 20)
crawler := func (url string, depth int) {
defer func() { ch <- Quit{} }()
body, urls, err := fetcher.Fetch(url)
if err != nil {
ch <- Msg{ fmt.Sprintf("%s\n", err) }
return
}
ch <- Msg{ fmt.Sprintf("found: %s %q\n", url, body) }
for _, u := range urls {
ch <- URL{ u, depth - 1 }
}
}
works := 0
memo := make(map[string]bool)
ch <- URL{ url, depth }
for {
req := <- ch
switch req := req.(type) {
case Msg:
fmt.Print(req.message)
case URL:
if req.depth > 0 && !memo[req.url] {
memo[req.url] = true
works++
go crawler(req.url, req.depth)
}
case Quit:
works--
}
if works <= 0 {
break
}
}
}
func main() {
Crawl("http://golang.org/", 4, fetcher)
}
type fakeFetcher map[string]*fakeResult
type fakeResult struct {
body string
urls []string
}
func (f fakeFetcher) Fetch(url string) (string, []string, error) {
time.Sleep(time.Second * 5)
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/",
},
},
}