gopl (the go programing language)部分练习(个人做的,看完书之前看能力更新)

最近在学习go语言,在看tour of go的时候发现上面的练习被贴出来不少,但是最近看gopl的时候发现书上的练习贴出来的很少,于是想贴出来自己的,都是自己做的,有问题请指教;如果有补充的可以联系,我会把相应代码段贴上来并且注上信息。

代码段大都是从github上下载下来然后修改的,版权都是书作者的,在代码段中就不注释了。我用的ide是Goland(推荐)。代码段中的os.Args()功能我用得很少,所需要的变量大都换成现成的了。

exercise1.7/page17

// Fetch prints the content found at each specified URL.
package main

import (
    "fmt"
    "net/http"
    "os"
    "io"
)

func main() {
    url:="http://gopl.io"//网址可以随意换
    resp, err := http.Get(url)
    if err != nil {
        fmt.Fprintf(os.Stderr, "fetch: %v\n", err)
        os.Exit(1)
    }
    _,err2:=io.Copy(os.Stdout,resp.Body)
    resp.Body.Close()
    if err2 != nil {
        fmt.Fprintf(os.Stderr, "fetch: reading %s: %v\n", url, err2)
        os.Exit(1)
    }
}

exercise1.12/page22

// Lissajous generates GIF animations of random Lissajous figures.
//简易版,只能修改cycles变量,并必须直接在/后输入数字,否则cycle默认是5
package main

import (
    "image"
    "image/color"
    "image/gif"
    "io"
    "math"
    "math/rand"
)

//!-main
// Packages not needed by version in book.
import (
    "log"
    "net/http"
    "time"
    "strconv"
)

//!+main

var palette = []color.Color{color.White, color.Black}

const (
    whiteIndex = 0 // first color in palette
    blackIndex = 1 // next color in palette
)

func main() {
    //!-main
    // The sequence of images is deterministic unless we seed
    // the pseudo-random number generator using the current time.
    // Thanks to Randall McPherson for pointing out the omission.
    rand.Seed(time.Now().UTC().UnixNano())
    //!+http
    handler := func(w http.ResponseWriter, r *http.Request) {
        cy,_:=strconv.Atoi(r.URL.Path[1:])
        lissajous(w,cy)
    }
    http.HandleFunc("/", handler)
    //!-http
    log.Fatal(http.ListenAndServe("localhost:8000", nil))
    return
}

func lissajous(out io.Writer, cy int) {
    const (
        //cycles  = 5     // number of complete x oscillator revolutions
        res     = 0.001 // angular resolution
        size    = 100   // image canvas covers [-size..+size]
        nframes = 64    // number of animation frames
        delay   = 8     // delay between frames in 10ms units
    )
    cycles:=5 //设置cycles变量
    if cy!=0 {
        cycles =cy
    }
    freq := rand.Float64() * 3.0 // relative frequency of y oscillator
    anim := gif.GIF{LoopCount: nframes}
    phase := 0.0 // phase difference
    for i := 0; i < nframes; i++ {
        rect := image.Rect(0, 0, 2*size+1, 2*size+1)
        img := image.NewPaletted(rect, palette)
        for t := 0.0; t < float64(cycles)*2*math.Pi; t += res {
            x := math.Sin(t)
            y := math.Sin(t*freq + phase)
            img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5),
                blackIndex)
        }
        phase += 0.1
        anim.Delay = append(anim.Delay, delay)
        anim.Image = append(anim.Image, img)
    }
    gif.EncodeAll(out, &anim) // NOTE: ignoring encoding errors
}

exercise3.4/page60

// Surface computes an SVG rendering of a 3-D surface function.
//只修改了main函数
package main

import (
    "fmt"
    "math"
    "io"
    "net/http"
    "log"
)

const (
    width, height = 600, 320            // canvas size in pixels
    cells         = 100                 // number of grid cells
    xyrange       = 30.0                // axis ranges (-xyrange..+xyrange)
    xyscale       = width / 2 / xyrange // pixels per x or y unit
    zscale        = height * 0.5       // pixels per z unit
    angle         = math.Pi / 6         // angle of x, y axes (=30°)
)

var sin30, cos30 = math.Sin(angle), math.Cos(angle) // sin(30°), cos(30°)

func main()  {
    handler := func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type","image/svg+xml")
        surface(w)
    }
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe("localhost:8000", nil))
    return
}
func surface(w io.Writer) {
    fmt.Fprintf(w,"<svg xmlns='http://www.w3.org/2000/svg' "+
        "style='stroke: grey; fill: white; stroke-width: 0.7' "+
        "width='%d' height='%d'>\n", width, height)
    for i := 0; i < cells; i++ {
        for j := 0; j < cells; j++ {
            ax, ay := corner(i+1, j)
            bx, by := corner(i, j)
            cx, cy := corner(i, j+1)
            dx, dy := corner(i+1, j+1)
            fmt.Fprintf(w,"<polygon points='%g,%g %g,%g %g,%g %g,%g'/>\n",
                ax, ay, bx, by, cx, cy, dx, dy)
        }
    }
    fmt.Fprintf(w,"</svg>\n")
}

func corner(i, j int) (float64, float64) {
    // Find point (x,y) at corner of cell (i,j).
    x := xyrange * (float64(i)/cells - 0.5)
    y := xyrange * (float64(j)/cells - 0.5)

    // Compute surface height z.
    z := f(x, y)

    // Project (x,y,z) isometrically onto 2-D SVG canvas (sx,sy).
    sx := width/2 + (x-y)*cos30*xyscale
    sy := height/2 + (x+y)*sin30*xyscale - z*zscale
    return sx, sy
}

func f(x, y float64) float64 {
    r := math.Hypot(x, y) // distance from (0,0)
    return math.Sin(r)/r
}

exercise4.1/page74

//did it by myself ,page 74
//comma2 can deal with floating-point number and an optional sign
package main

import (
    "fmt"
    "bytes"
    "strings"
)

func comma(s string)string  {
    var buf bytes.Buffer
    n,l:=0,len(s)
    if s[0]=='-'||s[0]=='+'{
        buf.WriteByte(s[0])
        n=1
    }
    if strings.Contains(s,"."){
        l=strings.Index(s,".")
    }
    for i:=n;i<l;i++{
        if (l-i)%3==0&&i>n{
            buf.WriteString(",")
        }
        fmt.Fprintf(&buf,"%c",s[i])
    }
    fmt.Fprintf(&buf,"%s",s[l:])
    return buf.String()
}
func main()  {
    s:="-311376114.7342424"
    fmt.Println(comma(s))
}

exercise4.1/page84

//如题模仿了2.6.2的方法,page 84
package main

import (
    "fmt"
    "crypto/sha256"
)
var pc[256]byte

func init()  {
    for i:=range pc{
        pc[i]=pc[i/2]+byte(i&1)
    }
}
func main()  {
    n:=0
    c1 := sha256.Sum256([]byte("x"))
    c2 := sha256.Sum256([]byte("X"))
    for i:=range c1{
        c1[i]&=c2[i]
        n+=int(pc[c1[i]])
    }
    fmt.Println(n)
}

exercise4.2/page84

//bufio的使用,page 84
package main

import (
    "bufio"
    "crypto/sha256"
    "crypto/sha512"
    "fmt"
    "os"
)

func main() {
    ch := 0
    if len(os.Args)>1 {
        flag := os.Args[1]
        if flag == "384" {
            ch = 1
        }
        if flag == "512" {
            ch = 2
        }
    }
    inputReader := bufio.NewReader(os.Stdin)
    fmt.Println("Please enter a string")
    input, err := inputReader.ReadString('\n')
    if err != nil {
        fmt.Println(err)
        return
    }
    switch ch {
    case 1:
        fmt.Println(sha512.Sum384([]byte(input)))
    case 2:
        fmt.Println(sha512.Sum512([]byte(input)))
    default:
        fmt.Println(sha256.Sum256([]byte(input)))
    }
}

exercise4.6/page93

//this piece of code is written by myself,page 94
package main

import (
    "fmt"
    "unicode"
    "unicode/utf8"
)

func main()  {
    bytes:=[]byte{'\t','\n','\v','a'}
    fmt.Println(bytes)//[9,10,11,128]
    bytes=elim(bytes)
    fmt.Println(bytes)//[11,97]
}

func elim(bytes []byte)[]byte{
    j:=0
    for i:=0;i<len(bytes)-1;{
        v1,_:=utf8.DecodeRune(bytes[i:])
        v2,_:=utf8.DecodeRune(bytes[i+1:]);
        if unicode.IsSpace(v1)&&unicode.IsSpace(v2){
            copy(bytes[i:],bytes[i+1:])
            bytes[i]=' '
            j++
        } else{
            i++
        }
    }
    return bytes[:len(bytes)-j]
}

exercise4.1/page99

//the usage of function bufio and scanner, did it myself, page 99
package main

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

func main() {
    rec:=make(map[string]int)
    file,err:=os.Open("hello.txt")
    if err!=nil{
        fmt.Println(err)
        return
    }
    input:=bufio.NewScanner(file)
    input.Split(bufio.ScanWords)
    for input.Scan(){
        rec[input.Text()]++
    }
    for i,v:=range rec{
        fmt.Println(i,v)
    }
}

exercise5.10/page140

//use maps instead of slices
func topoSort(m map[string][]string) []string {
    var order []string
    seen := make(map[string]bool)
    var visitAll func(items map[string]bool)

    visitAll = func(items map[string]bool) {
        for item := range items {
            if !seen[item] {
                seen[item] = true
                order = append(order, item)
                nums2:=make(map[string]bool)
                for _,nu:=range m[item]{
                    nums2[nu]=true
                }
                visitAll(nums2)
                //order = append(order, item)
            }
        }
    }
    nums:=make(map[string]bool)
    for num:=range m{
        nums[num]=true
    }
    visitAll(nums)
    return order
}

exercise5.17/page143

//the package html needs the command:"go get ... " and vpn
//the code is modified from "gopl.io/ch5/links.go"
package main

import (
    "fmt"
    "net/http"

    "golang.org/x/net/html"
)

func main() {
    url:="http://gopl.io"
    resp, err := http.Get(url)
    if err != nil {
        fmt.Println("get failed")
        return
    }
    if resp.StatusCode != http.StatusOK {
        resp.Body.Close()
        fmt.Errorf("getting %s: %s", url, resp.Status)
    }
    doc, err := html.Parse(resp.Body)
    resp.Body.Close()
    if err != nil {
        fmt.Errorf("parsing %s as HTML: %v", url, err)
    }
    t:=ElementsByTagName(doc,"a")
    for _,v:=range t{
        fmt.Println(v)
    }
}

//returns the elements whose data matches one of the slice name
func ElementsByTagName (doc *html.Node,name...string)[]*html.Node{
    var nodes []*html.Node
    for _,s:=range name{
        visitNode := func(n *html.Node) {
            if n.Type == html.ElementNode && n.Data == s{
                    nodes = append(nodes, n)
                }
            }
        forEachNode(doc, visitNode, nil)
    }
    return nodes
}
// Copied from gopl.io/ch5/outline2.
func forEachNode(n *html.Node, pre, post func(n *html.Node)) {
    if pre != nil {
        pre(n)
    }
    for c := n.FirstChild; c != nil; c = c.NextSibling {
        forEachNode(c, pre, post)
    }
    if post != nil {
        post(n)
    }
}

exercise5.18/page149

/the "defer" statement can deal with the "return" value, marvelous! Only "Fetch" is here since nothing else has been changed
// Fetch saves the contents of a URL into a local file.
// Fetch downloads the URL and returns the
// name and length of the local file.
func fetch(url string) (filename string, n int64, err error) {
    resp, err := http.Get(url)
    if err != nil {
        return "", 0, err
    }
    defer resp.Body.Close()

    local := path.Base(resp.Request.URL.Path)
    if local == "/" {
        local = "index.html"
    }
    f, err := os.Create(local)
    if err != nil {
        return "", 0, err
    }
    defer func() {
        if err==nil{
            err=f.Close()
        }
        f.Close()
    }()
    n, err = io.Copy(f, resp.Body)
    return local, n, err
}

exercise5.19/page153

//I found that if a function which has a value to return ends with the "panic" statement, "return" statement is not necessary 
package main

import "fmt"

func noret() (err error){
    defer func(){
        if p:=recover();p!=nil{
            err=fmt.Errorf("%v",p)
        }
    }()
    panic("google")
}
func main()  {
    a:=noret()
    fmt.Println(a)
}

exercise6.1&6.2/page167

//the method remove is an enhanced version which removes useless slice elements when removing
func (s *IntSet) Add(x ...int) {
    for _,x:=range x {
        word, bit := x/64, uint(x%64)
        for word >= len(s.words) {
            s.words = append(s.words, 0)
        }
        s.words[word] |= 1 << bit
    }
}

func (s *IntSet) Len() int {
    return len(s.words)
}

func (s *IntSet) Clear() {
    s.words = nil
}

func (s *IntSet) Remove(x ...int) {
    for _,x:=range x {
        word, bit := x/64, uint(x%64)
        if s.Has(x) {
            s.words[word] ^= 1 << bit
            for lent := len(s.words) - 1; s.words[lent] == 0; lent-- {
                if lent == 0 {
                    s.Clear()
                    break
                }
                s.words = s.words[:lent]
            }
        }
    }
}

func (s *IntSet) Copy() *IntSet  {
    t:= IntSet{}
    copy(t.words,s.words)
    return &t
}

exercise7.1/page173

//"scanner" is very useful
type WordCounter int

func (w *WordCounter)Write(p []byte)(int, error)  {
    s:=bytes.NewReader(p)
    bs:=bufio.NewScanner(s)
    bs.Split(bufio.ScanWords)
    for bs.Scan(){
        *w++
    }
    return int(*w),nil
}

type LineCounter int
func (l *LineCounter)Write(p []byte)(int ,error){
    s:=bytes.NewReader(p)
    bs:=bufio.NewScanner(s)
    bs.Split(bufio.ScanLines)
    for bs.Scan(){
        *l++
    }
    return int(*l),nil
}

exercise7.2/page174

//I am not sure whether it's right
func CountingWriter(w io.Writer)(io.Writer, *int64)  {
    var w1 io.Writer
    w1=w
    var buf bytes.Buffer
    fmt.Fprint(&buf,w1)
    ln:=int64(len(buf.Bytes()))
    return w1,&ln
}

exercise7.3/page174

//easy inorder traversal, not sure of the correctness 
func (t *tree) String() (s string) {
    if t != nil {
        if t.left!=nil{
            s +=t.left.String()
        }
        s += strconv.Itoa(t.value)+" "
        if t.right!=nil {
            s +=t.right.String()
        }
    }
    return s
}

exercise7.4/page175

//my own newreader function 
//almost copy from the package "strings", the interface 
//"Reader" is very useful
type Reader struct{
    s string
    i int   //current reading index
}

func NewReader(s string) *Reader {
    return &Reader{s,0}
}

func (r *Reader) Read(b []byte) (n int, err error) {
    if len(b)==0{
        return 0,nil
    }
    if r.i>=len(r.s){
        return 0,io.EOF
    }
    n=copy(b,r.s[r.i:])
    r.i+=n
    return
}

exercise7.4/page175

//not sure of the correctness
func LimitReader(r io.Reader,n int64)io.Reader{
    var buf bytes.Buffer
    fmt.Fprint(&buf,r)
    if int64(len(buf.Bytes()))>n{
        return bytes.NewReader(buf.Bytes()[:n])
        panic(io.EOF)
    }
    return bytes.NewReader(buf.Bytes())
}

exercise7.11/page195

//other functions are similar to this
type dollars float32

func (d dollars) String() string { return fmt.Sprintf("$%.2f", d) }

type database struct {
    data map[string]dollars
    mu   sync.Mutex
}

func (db database) create(w http.ResponseWriter, req *http.Request) {
    db.mu.Lock()
    item := req.URL.Query().Get("item")
    if _, ok := db.data[item]; ok {
        w.WriteHeader(http.StatusNotFound)
        fmt.Fprintf(w, "already exists! item: %v ", item)
        defer db.mu.Unlock()
        return
    }
    price, _ := strconv.ParseFloat(req.URL.Query().Get("price"), 32)
    if price < 0 {
        w.WriteHeader(http.StatusNotFound)
        fmt.Fprintf(w, "can not be negative! price: %v", item)
        defer db.mu.Unlock()
        return
    }
    db.data[item] = dollars(price)
    fmt.Fprintf(w,"create complete:\n%v: %v\n",item,price)
    db.mu.Unlock()
}
func main() {
    db := database{map[string]dollars{"shoes": 50, "socks": 5}, sync.Mutex{}}
    http.HandleFunc("/list", db.list)
    http.HandleFunc("/price", db.price)
    http.HandleFunc("/create", db.create)
    http.HandleFunc("/update", db.update)
    http.HandleFunc("/delete", db.delete)
    log.Fatal(http.ListenAndServe("localhost:8000", nil))
}

exercise7.12/page195

/*纸上得来终觉浅,绝知此事要躬行!书上的练习做了之后才理解更深刻!而且更加强了找相关 信息的能力,模仿也很重要,虽然可能对于厉害的人来说这很简单,但是做出来这道练习我还是很开心的,让我对之前的看过的内容有了新的认识*/
func (db database) list(w http.ResponseWriter, req *http.Request) {
    List.Execute(w, db)
}

var List = template.Must(template.New("List").Parse(`
<h1>list</h1>
<table>
<tr style='text-align: left'>
  <th>Item</th>
  <th>Price</th>
</tr>
{{range $k,$v :=.}}
<tr>
  <td>{{$k}}</td>
  <td>{{$v}}</td>
</tr>
{{end}}
</table>
`))

exercise8.1/page222

8.1完成得有问题,无法按表格在原位置输出时间
port.go

///port.go realizes the portFlag,模仿的书上的flag样例
package port

import (
    "fmt"
    "flag"
)
type Port string
type portFlag struct{
    TZ string
    Port
}

func (p portFlag)String ()string{
    return fmt.Sprintf("Timezone: %s, Port:%s",p.TZ,p.Port)
}

func (p *portFlag)Set (s string)error{
    p.Port=Port(s)
    switch s{
    case "8010":
        p.TZ="NewYork"
        return nil
    case "8020":
        p.TZ="London"
        return nil
    case "8030":
        p.TZ="Tokyo"
        return nil
    }
    return fmt.Errorf("invalid port %q",s)
}
func PortFlag(name string, value Port,usage string)*portFlag  {
    f:=portFlag{"Beijing",value}
    flag.CommandLine.Var(&f,name,usage)
    return &f
}

clock.go

// Clock is a TCP server that periodically writes the time.
package main

import (
    "io"
    "log"
    "net"
    "time"

    "gopl.io/ch8/port"
    "flag"
)

var portflag=port.PortFlag("port","8000","the port")

func handleConn(c net.Conn) {
    defer c.Close()
    for {
        _, err := io.WriteString(c, portflag.TZ+": "+time.Now().Format("15:04:05\n"))
        if err != nil {
            return // e.g., client disconnected
        }
        time.Sleep(1 * time.Second)
    }
}

func main() {
    flag.Parse()
    listener, err := net.Listen("tcp", "localhost:"+string(portflag.Port))
    if err != nil {
        log.Fatal(err)
    }
    //!+
    for {
        conn, err := listener.Accept()
        if err != nil {
            log.Print(err) // e.g., connection aborted
            continue
        }
        go handleConn(conn) // handle connections concurrently
    }
    //!-
}

clockwall.go

// clockwall is a read-only TCP client.
package main

import (
    "io"
    "log"
    "net"
    "os"
)

func main() {
    go call("8010")
    go call("8020")
    call("8030")
}

func mustCopy(dst io.Writer, src io.Reader) {
    if _, err := io.Copy(dst, src); err != nil {
        log.Fatal(err)
    }
}
func call(port string)  {
    conn, err := net.Dial("tcp", "localhost:"+port)
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()
    mustCopy(os.Stdout, conn)
}

虽然没什么重要的,但是如果转载请注明作者和网址,谢谢!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值